Почему контейнеры МОК рассматриваются как способ уменьшения сцепления? - PullRequest
1 голос
/ 28 августа 2011

Я думаю об использовании DI и Unity в моем проекте.И у меня вопрос: как это уменьшит сцепление?С моей точки зрения, это увеличивает связь, потому что:

  1. Мне нужно создать UnityContainer и зарегистрировать там все типы.Это означает, что мне нужно иметь ссылку на все сборки в сборке, где создается этот контейнер.

    IUnityContainer UnityContainer;
    //....
    IUnityContainer UnityContainer= new UnityContainer();
    UnityContainer.RegisterType<IMyService, CustomerService>();
    
  2. Мне нужно создать экземпляр моей службы с помощью Resolve, но это означает, чтоМне нужна ссылка на сборку с контейнером.

    var service = SomeClassWithContainer.UnityContainer.Resolve<IMyService>();
    

Я что-то не так понял или на самом деле это увеличение сцепления?

Ответы [ 2 ]

9 голосов
/ 28 августа 2011

Я думаю, вы не поняли, как должны быть разрешены ваши зависимости.

1.) Ссылка на Unity необходима только в вашем коде начальной загрузки, который находится в единственном центральном месте вашего приложения.

2.) Как только начальная загрузка завершена, все зависимости (в идеале) разрешаются с помощью инжектора конструктора, который автоматически выполняется Unity, если содержащий класс разрешается с помощью Unity - он стекает по графу объектов. Пример, который вы используете, на самом деле является просто шаблоном «локатора службы», а не DI.

Это уменьшает сцепление, поскольку вместо непосредственного создания конкретного класса, от которого зависит ваш класс, вы «внедряете» зависимости (опять же, в идеале, некоторую абстракцию, например, интерфейс) в ваш класс, что позволяет вам заменить эти зависимости другими классами, т.е. Сценарий модульного тестирования.

6 голосов
/ 28 августа 2011

Ваш вопрос содержит пример антишаблона «Локатор служб»:

public class UsesMyService
{
    private readonly IMyService _service;

    public UsesMyService()
    {
        _service = SomeClassWithContainer.UnityContainer.Resolve<IMyService>();
    }
}

Это принципиально отличается от шаблона внедрения зависимостей из-за направления потоков информации: в приведенном выше примере вы обращаетесь ки запросить для службы, тогда как в приведенном ниже примере вы вручили службу:

public class UsesMyService
{
    private readonly IMyService _service;

    public UsesMyService(IMyService service)
    {
        _service = service;
    }
}

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

Как они вообще могут знать, что настраивать?Им потребуется либо исходный код, либо некоторая документация, сообщающая им, что класс зависит от IMyService.Параметр конструктора четко выражает это требование для потребителей без какой-либо внешней ссылки.

Если вы будете следовать этому шаблону во всех своих библиотеках, вы возьмете на себя ответственность за сборку объектов вплоть до самого внешнего слоя, известного как корень композиции,Это единственное место, обычно класс приложений верхнего уровня, является единственным местом со ссылками на все библиотеки, которые вы используете. Это , где находится контейнер, и никакой другой класс во всем вашем решении не должен ссылаться на него.

...