Общая практика IoC - неправильно ли, чтобы услуги зависели друг от друга? - PullRequest
7 голосов
/ 13 февраля 2012

Сейчас у меня есть несколько служб, которые определены в сборке, которая не зависит от контейнера IoC (в моем случае это Ninject). В основном проекте у меня есть IRepository для доступа к данным, зарегистрированным в контейнере.

this.Bind<IRepository>().To<EntityFrameworkRepository<MyDatabaseEntities>>();

У меня также зарегистрированы службы IAuthenticationService и IErrorLogger, в чьей конкретной реализации я хочу использовать репозиторий для их логики. Тем не менее, я не уверен, как лучше всего добиться этого. В настоящее время мой конструктор в обеих конкретных реализациях принимает параметр IRepository, и я передаю его при регистрации:

this.Bind<IAuthenticationService>().To<MyAuthenticationService>().
                WithConstructorArgument("myRepository", ctx => ctx.Kernel.Get<IRepository());

Здесь я просто говорю контейнеру захватить экземпляр IRepository и передать его конструктору.

Я не чувствовал себя правильно из-за того, что моя сервисная сборка зависела от ninject или даже от общего сервисного локатора (CSL), но я также не уверен в своем текущем способе. Я ищу мнения и альтернативные решения.

Если мои другие сервисы не используют IRepository, мне придется создавать новые конкретные реализации этих сервисов для каждого типа базового типа IRepository (например, AuthenticationService как для поддельных, так и для реальных данных). Было бы много логических повторений.

1 Ответ

6 голосов
/ 13 февраля 2012

Ваша сервисная сборка не должна зависеть от Ninject, только от интерфейсов, для которых вы регистрируете свои конкретные типы.Контейнер IoC должен быть только агрегатным корнем для внедрения зависимостей в ваши классы.С другой стороны, сборка, содержащая совокупный корень / ядро ​​Ninject, будет зависеть от всех сборок, содержащих конкретные типы (как еще она сможет их разрешить?).

В целом с IoCвы должны применить голливудский принцип здесь - вы должны дать зависимости для ваших конкретных экземпляров объекта (используя инжектор конструктора, если это вообще возможно), не позволяйте экземплярам объекта ask для их зависимостей.

Пример, который вы используете для WithConstructorArgument(), на самом деле вообще не нужен, поскольку разрешение зависимостей работает рекурсивно: вы зарегистрировали и IRepository, и IAuthenticationService с контейнером, поэтомуон знает, как решить оба.Поскольку IAuthenticationService связан с AuthenticationService, вам не нужно указывать аргумент конструктора, поскольку он имеет тип IRepository и будет разрешен автоматически.

Что касается повторения - конечно, вам придетсясоздайте различные реализации для IRepository для разных типов репозиториев, предполагая, что вы хотите различное поведение этих репозиториев.

...