Недавно я обсуждал принцип инверсии зависимостей, инверсию управления и инжекцию зависимостей. В отношении этой темы мы обсуждали, нарушают ли эти принципы один из столпов ООП, а именно инкапсуляцию.
Мое понимание этих вещей:
- Принцип инверсии зависимостей подразумевает, что объекты должны зависеть от абстракций, а не от конкреций - это основной принцип, на котором реализована инверсия шаблона управления и инъекции зависимостей.
- Инверсия управления - это реализация шаблона принципа инверсии зависимостей, где абстрактные зависимости заменяют конкретные зависимости, позволяя конкретизировать зависимость, которая должна быть указана вне объекта.
- Injection Dependency - это шаблон проектирования, который реализует Inversion of Control и обеспечивает разрешение зависимостей. Инъекция происходит, когда зависимость передается зависимому компоненту. По сути, шаблон Injection Dependency предоставляет механизм для объединения абстракций зависимостей с конкретными реализациями.
- Инкапсуляция - это процесс, при котором данные и функциональные возможности, требуемые объектом более высокого уровня, изолированы и недоступны, поэтому программист не знает, как реализован объект.
Дебаты получили точку со следующим утверждением:
IoC не является ООП, потому что он прерывает инкапсуляцию
Лично я считаю, что принцип инверсии зависимостей и инверсия шаблона управления должны соблюдаться религиозно всеми разработчиками ООП, и я живу по следующей цитате:
Если есть (потенциально) более одного способа скинуть кошку, то неведите себя так, как будто есть только один.
Пример 1:
class Program {
void Main() {
SkinCatWithKnife skinner = new SkinCatWithKnife ();
skinner.SkinTheCat();
}
}
Здесь мы видим пример инкапсуляции. Программисту нужно только позвонить Main()
, а кошка будет обложена, но что, если он хочет одеть кошку, скажем, с острыми зубами бритвы?
Пример 2:
class Program {
// Encapsulation
ICatSkinner skinner;
public Program(ICatSkinner skinner) {
// Inversion of control
this.skinner = skinner;
}
void Main() {
this.skinner.SkinTheCat();
}
}
... new Program(new SkinCatWithTeeth());
// Dependency Injection
Здесь мы наблюдаем принцип инверсии зависимостей и инверсию управления, так как абстрактный (ICatSkinner
) предоставляется для того, чтобы позволить конкретным зависимостям быть переданными программистом. Наконец, есть несколько способов обмануть кошку!
Ссора здесь; это разрушает инкапсуляцию? технически можно утверждать, что .SkinTheCat();
по-прежнему инкапсулируется в вызов метода Main()
, поэтому программист не знает о поведении этого метода, поэтому я не думаю, что это нарушает инкапсуляцию.
Делившись немного глубже, я думаю, что IoC контейнеры ломают OOP, потому что они используют отражение, но я не уверен, что IoC нарушает OOP, и я не уверен, что IoC нарушает инкапсуляцию. На самом деле я бы сказал, что:
Инкапсуляция и инверсия управления совпадают друг с другом счастливо, позволяя программистам проходить только конкреции зависимость, в то же время скрывая общую реализацию посредством инкапсуляция.
Вопросы:
- Является ли IoC прямой реализацией принципа инверсии зависимостей?
- Всегда ли IoC прерывает инкапсуляцию и, следовательно, ООП?
- Следует ли использовать IoC экономно, религиозно или надлежащим образом?
- В чем разница между IoC и контейнером IoC?