Как связаны инверсия управления, принцип инверсии зависимости и инъекция зависимости?

Я знаю, что с помощью Dependency Injection/ шаблона проектирования службы / и т. Д. мы достигаем инверсии контроля. но куда вписывается принцип обращения зависимости? или это совершенно отдельно, чем эти 2?

  1. Достигаем ли мы МОК, используя DIP?
  2. DIP как-то относится к IOC или DI?

2 ответа

Например, если у класса A есть зависимость от класса B, рефакторинг ее посредством инверсии зависимостей приведет к тому, что класс A будет зависеть от интерфейса B, который реализуется классом B.

  • До рефакторинга: класс A ---> класс B
  • После рефакторинга: класс A ---> интерфейс B <--- класс B

В двух словах, принцип инверсии зависимостей гласит, что как ваши абстракции высокого уровня (например, класс A), так и абстракции низкого уровня (например, класс B) не должны зависеть от чего-то конкретного (поскольку класс A зависел от класса B перед рефакторингом).), но быть отделенным средним абстрактным слоем (абстракция интерфейса B).

Инверсия зависимостей используется как средство реализации внедрения зависимостей. Например, весной

interface AbstractB {

}

@Component
class ConcreteB implements AbstractB {

}

@Component 
class ConcreteA {

    @Autowired
    // note reference type is AbstractB
    private AbstractB concreteB;

}
  • В зависимости от ссылки типа AbstractB (вместо ConcreteB) в ConcreteA мы применяем инверсию зависимостей.
  • Используя @Autowired и позволяя Spring внедрить эту зависимость для нас (вместо того, чтобы создавать ее самостоятельно с помощью ключевого слова 'new'), мы используем внедрение зависимостей.
  • Инверсия управления - это принцип, позволяющий внешней структуре (в данном примере, контейнеру Spring IoC) создавать экземпляры ваших зависимостей и внедрять их в ваш код.

Относительно "Достигаем ли мы МОК, используя также DIP?", На мой взгляд, не обязательно, поскольку мы могли бы автоматически соединяться с эталоном типа ConcreteB, достигая IoC и DI, но нарушая DIP.

Отвечает ли это на ваш вопрос?

Инверсия контроля - это принцип, который делает то, что утверждает, что делает. Он обратит контроль над любой дополнительной ответственностью, которую класс имеет помимо своей, другому классу, чтобы справиться с этой ответственностью, чтобы получить связь с Loos.

Скажем

class Service_A
{
    Service_B _service = new Service_B();

    void DoSomething()
    {
        _service.DoSomething_B();
    }
}

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

Теперь, используя IoC, мы можем перевернуть ответственность за создание Service_B для некоторой фабрики.

class ServiceFactory
{
     private  ServiceFactory()
     {
     }

     private static ServiceFactory _instance = new ServiceFactory();
     public ServiceFactory Instance { get { return _instance; } }

     public Service_B GetInstance() 
     {
          return new Service_B();
     }     
}

И использовать его в Service_A вроде

class Service_A
{
    Factory _factory;

    void DoSomething()
    {
        _factory.Instance.GetInstance().DoSomething_B();
    }
}

Так что теперь у вас есть связь по двум объектам, Service_A получает действительный экземпляр, предоставленный ServiceFactory, который имеет дело со сложностью создания действительного экземпляра Service_B (не так сложно в этом примере, но идея есть)

Инверсия зависимости -> это принцип, который гласит, что модули более высокого уровня должны зависеть от абстракций. Что это значит? это вводит уровень абстракции, интерфейс. Итак, вы определяете абстракцию

interface IService_B 
{
    void DoSomething_B();
}

Реализация.

class Service_B : IService_B
{
   void IService_B.DoSomething_B()
   {

   }
} 

Итак, что мы определили здесь, это уровень абстракции, от которого будет зависеть наш более высокий уровень, в нашем случае Serivice_A

Так что рефакторинг нашей фабрики IoC

class ServiceFactory
{
     private  ServiceFactory()
     {
     }

     private static ServiceFactory _instance = new ServiceFactory();
     public ServiceFactory Instance { get { return _instance; } }

     public IService_B GetInstance() 
     {
          return new Service_B();
     }     
}

Обратите внимание, что мы возвращаем вместо Service_B IService_B. Так что же это действие приносит на стол? хорошо, тот факт, что теперь мы зависим от абстракции, а не от деталей реализации (полное определение DiP: модули высокого уровня должны зависеть от абстракций, абстракции не должны зависеть от деталей), мы можем полностью отделить Service_A от Service_B. Структура будет выглядеть так

Dependency graph 

Service_A.dll
     |
     +
IService_B.dll  
     +
     |
Service_B.dll

Обратите внимание, что у нас нет прямой зависимости от B от A, как в предыдущем случае, когда Factory возвратила Service_B.

И более высокий уровень абстракции

class Service_A
{
    IService_B _service;

    Service_A()
    {
        _service = ServiceFactory.Instance.GetInstance()
    }     

    void DoSomething()
    {
        _service.DoSomething_B();
    }
} 

Таким образом, на данный момент мы слабо связаны и основываемся на абстракциях.

Dependency Injection -> - это шаблон, который разрешает зависимости посредством внедрения (конструктор должен обрабатываться всеми контейнерами IoC, поэтому я буду придерживаться этого)

Вот так выглядит внедрение зависимости через конструктор

class Service_A
{
    IService_B _service;

    Service_A(IService_B service)
    {
        _service = service
    }     

    void DoSomething()
    {
        _service.DoSomething_B();
    }
} 

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

  class Consumer 
  {
       public void Doing()
       {
            new Service_A(ServiceFactory.Instance.GetService());
       }
  }

Итак, как очень короткий вывод, это отношение.

IoC + DiP => IoC Контейнеры

Внедрение зависимостей использует контейнеры IoC

Я также рекомендую https://www.youtube.com/watch?v=5lIeky2V4dc

Другие вопросы по тегам