Инъекция зависимостей и круговая ссылка - PullRequest
3 голосов
/ 18 сентября 2008

Я только начинаю с DI и модульного тестирования и попал в ловушку, которая, я уверен, не составляет труда для более опытных разработчиков:

У меня есть класс под названием MessageManager, который получает данные и сохраняет их в БД. В той же сборке (проект в Visual Studio) я создал интерфейс репозитория со всеми методами, необходимыми для доступа к БД. Конкретная реализация этого интерфейса находится в отдельной сборке под названием DataAccess.

Таким образом, для DataAccess необходима ссылка на проект MessageManager, чтобы узнать об интерфейсе хранилища. А MessageManager нужна ссылка на проект для DataAccess, чтобы клиент MessageManager мог внедрить конкретную реализацию интерфейса репозитория. Это конечно не разрешено

Я мог бы переместить интерфейс в сборку доступа к данным, но я считаю, что интерфейс хранилища должен находиться в той же сборке, что и клиент, который его использует

Так что я сделал не так?

Ответы [ 7 ]

3 голосов
/ 18 сентября 2008

Вы должны отделить свой интерфейс от любой сборки. Помещение интерфейса вместе с потребителем или разработчиком отрицает необходимость иметь интерфейс.

Цель интерфейса - позволить вам внедрить любой объект, который реализует этот интерфейс, независимо от того, принадлежит ли он той же сборке, к которой принадлежит ваш объект DataAccess. С другой стороны, вы должны разрешить MessageManager использовать этот интерфейс без какой-либо конкретной реализации.

Поместите ваш интерфейс в другой проект, и проблема решена.

2 голосов
/ 18 сентября 2008

У вас есть только два варианта: добавить сборку для хранения интерфейса или переместить интерфейс в сборку DataAccess. Даже если вы разрабатываете архитектуру, в которой когда-нибудь класс DataAccess может быть заменен другим разработчиком (даже в другой сборке) интерфейса репозитория, нет причин исключать его из сборки DataAccess.

1 голос
/ 18 сентября 2008

Используете ли вы инверсию контрольного контейнера? Если так, ответ прост.

Сборка А содержит:

  • MessageManager
  • IRepository
  • ContainerA (добавить MessageManager)

Сборка B содержит (и ref сборка A):

  • Репозиторий реализует IRepository
  • ContainerB расширяет ContainerA (добавить репозиторий)

Сборка C (или B) запускает приложение / запрашивает контейнер для MessageManager, который знает, как разрешить MessageManager и IRepository.

1 голос
/ 18 сентября 2008

Часто вы можете решить проблемы с циклическими ссылками, используя инжектор сеттера вместо инжектора конструктора.

В псевдокоде:

Foo f = new Foo();
Bar b = new Bar();
f.setBar(b);
b.setFoo(f);
1 голос
/ 18 сентября 2008

Я думаю, вам следует перенести интерфейс репозитория в сборку DataAccess. Тогда DataAccess больше не будет ссылаться на MessageManager.

Однако сказать сложно, поскольку я почти ничего не знаю о вашей архитектуре ...

0 голосов
/ 19 сентября 2008

Инверсия зависимостей в игре:

Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

Абстракция, от которой зависят классы в сборке DatAccess, должна находиться в отдельной сборке от классов DataAccess и конкретной реализации этой абстракции (MessageManager).

Да, это больше сборок. Лично это не имеет большого значения для меня. Я не вижу большого недостатка в дополнительных сборках.

0 голосов
/ 18 сентября 2008

Вы можете оставить структуру в том виде, в каком она у вас есть (без зависимости от MessageManager до DataAccess, которая вызывает проблему), и затем MessageManager динамически загружать конкретную реализацию, требуемую во время выполнения, используя класс System.Reflection.Assembly.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...