Как связаны инверсия управления, принцип инверсии зависимости и инъекция зависимости?
Я знаю, что с помощью Dependency Injection/ шаблона проектирования службы / и т. Д. мы достигаем инверсии контроля. но куда вписывается принцип обращения зависимости? или это совершенно отдельно, чем эти 2?
- Достигаем ли мы МОК, используя DIP?
- 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