Я разрабатываю систему, которая предоставляет веб-сервис для доступа к своей базе данных и предоставляет его через классы .NET. Наш обычный способ работы - создавать экземпляр класса веб-службы всякий раз, когда нам нужно получить доступ к базе данных и напрямую использовать этот экземпляр; это, конечно, полностью идет вразрез с IoC и создает в основном непроверяемый код. Сейчас я пытаюсь разработать новый стандартный способ работы с использованием IoC, чтобы позволить нам писать (более) твердотельный код.
Мое текущее решение таково (не очень хорошо объяснено):
Веб-служба заключена в класс 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
, потому что им нужны одинаковые базовые способности, и тогда (не позднее) вся конструкция становится довольно зловещей.
Я полагаю, что в какой-то момент я ошибся, и теперь совершенно на неправильном пути. Как должна выглядеть структура такого решения? Будем очень благодарны за любой толчок в правильном направлении.
Edit:
@ Ответ Тобиаса заставил меня осознать, что я забыл важную деталь: есть две разные версии веб-службы с почти одинаковыми возможностями, но совершенно разными API, и это одна из причин, по которой у есть быть инкапсулированным.
Еще одно: если мои логические классы обращаются к веб-сервису напрямую (или через интерфейс), они также занимаются построением запросов веб-сервиса во всех деталях, что делает гораздо более тесно связанный код (тот, который мы до сих пор производил) и нарушает SRP - отсюда идея интерфейса соединителя.