Я разрабатываю систему, которая предоставляет веб-службу для доступа к своей базе данных и предоставляет ее через классы .NET. Наш обычный способ работы заключается в создании экземпляра класса веб-службы всякий раз, когда нам нужно получить доступ к базе данных и напрямую использовать этот экземпляр; это, конечно, полностью противоречит IoC и создает в основном непроверяемый код. Сейчас я пытаюсь разработать новый стандартный способ работы с использованием IoC, чтобы мы могли писать (больше) SOLID-кода.
Мое текущее решение таково (не очень хорошо объяснено):
Веб-служба заключена в класс DatabaseConnection
, который хранит объект веб-службы в качестве защищенного члена и предоставляет доступ к ряду часто используемых общих вызовов базы данных.
Когда мне нужен доступ к базе данных в реальном приложении, я наследую от этого класса (вызывая новый класс, скажем, ApplicationDatabaseConnection
) и реализую необходимые взаимодействия с базой данных в методах, которые затем могут вызывать веб-службу.
Этот класс не используется непосредственно в приложении, но предоставляет интерфейсы «соединителя» для различных частей приложения, каждая из которых представлена моделью контроллера/представления, подобной классу на верхнем уровне. Всякий раз, когда вызывается одна из этих функций приложения (например, из пользовательского интерфейса), создается соответствующий объект контроллера и передается мой объект ApplicationDatabaseConnection
в качестве реализации соответствующего интерфейса «соединителя», поэтому доступ к базе данных в этот момент правильно инкапсулируется и отделяется, как насколько я могу судить.
Моя проблема с этим такова: хотя это первый случай, когда я нашел фактическое использование ISP (принцип разделения интерфейса) в моем собственном коде (хотя я далеко не уверен, действительно ли это разумное использование концепции), я боятся, что этот класс может сделать слишком много и нарушить SRP (принцип единой ответственности). Или «только предоставление доступа к базе данных, хотя и для нескольких разных потребителей» является единой обязанностью?
Чтобы, возможно, сделать это немного яснее, вот примерно как будут выглядеть соответствующие классы:
DatabaseConnection
protected m_webservice
public OftenUsedDatabaseAccess()
ApplicationDatabaseConnection : DatabaseConnection, IConnectorA, IConnectorB
public IConnectorA.RetrieveRecords(fieldValue)
public IConnectorB.WriteStuff(listOfStuff)
FunctionAController
private m_IConnectorA
FunctionBController
private m_IConnectorB
Альтернативы, которые я могу придумать, тоже не кажутся мне идеальными.
Чтобы разделить функциональность доступа к базе данных, класс ApplicationDatabaseConnection
может быть только фабричным классом с Create
методами для разных соединителей (за интерфейсами IConnectorAFactory
, IConnectorBFactory
), но на самом деле там нет ничего, что требовало бы фабричного шаблона; я ничего не знаю только при создании экземпляров объектов «контроллер».
Кроме того, фактические классы коннекторов, по сути, также должны быть производными от DatabaseConnection
, потому что им нужны одни и те же базовые способности, и тогда (самое позднее) вся конструкция становится довольно зловещей.
Я полагаю, что в какой-то момент своего мышления я свернул не в ту сторону, и теперь я полностью на ложном пути. Как должна выглядеть структура такого решения? Любой толчок в правильном направлении будет принят с благодарностью.
Изменить:
Ответ @Tobias заставил меня понять, что я забыл важную деталь: существуют две разные версии веб-службы с практически одинаковыми возможностями, но совершенно разными API, что является одной из причин, почему он должен быть инкапсулированы.
Другой момент заключается в том, что если мои логические классы обращаются к веб-службе напрямую (или через интерфейс), они также занимаются построением запросов веб-службы во всех их деталях, что делает код гораздо более тесно связанным (такой, какой мы использовали). производит до сих пор) и нарушает SRP - отсюда и идея интерфейса коннектора.