Я понимаю ваше замешательство, и мне потребовалось некоторое время, чтобы понять, как эти понятия связаны друг с другом.Вот мое (как бы личное) объяснение всего этого:
1.Инверсия управления
Инверсия управления - это довольно общий принцип проектирования, который относится к отделению спецификации поведения от момента его фактического выполнения.Сравните, например,
myDependency.doThis();
с
myDependency.onEventX += doThis();
В последнем случае нет прямого вызова , что является более гибким.В общем виде инверсия управления относится к схеме наблюдателя , событиям или обратным вызовам .
2.Инверсия зависимостей
Инверсия зависимостей - еще один принцип проектирования.Грубо говоря, это говорит о том, что абстракция более высокого уровня не должна напрямую зависеть от абстракций более низкого уровня;это действительно приводит к разработке, в которой абстракция более высокого уровня не может быть повторно использована без абстракций более низкого уровня.
class MyHighLevelClass {
MyLowLevelClass dep = new MyLowLeverClass();
}
class App {
void main() { new HighLevelClass().doStuff(); }
}
Здесь MyHighLevelClass
не может скомпилироваться без доступа к MyLowLevelClass
.Чтобы разорвать эту связь, нам нужно абстрагировать класс низкого уровня с интерфейсом и удалить прямую реализацию.
class MyLowLevelClass implements MyUsefulAbstraction { ... }
class MyHighLevelClass {
MyUsefulAbstraction dep;
MyHighLevelClass( MyUsefulAbstraction dep ) {
this.dep = dep;
}
}
class App {
void main() { new HighLevelClass( new LowLevelClass() ).doStuff(); }
}
Обратите внимание, что вам не нужно ничего особенного, например, контейнер, для обеспечения инверсии зависимостей, что является принципом.Хорошее чтение: Принцип инверсии зависимости от дяди Боба.
3.Внедрение зависимостей
Теперь идет внедрение зависимостей.Для меня dependency injection = IoC + dependency inversion
:
- зависимости предоставляются извне, поэтому мы применяем принцип инверсии зависимостей
- контейнер устанавливает зависимости (не мы), поэтому мы говорим об инверсии управления
В приведенном выше примере внедрение зависимостей может быть выполнено, если контейнер используется для создания экземпляров объектов и автоматически вводит зависимость в конструктор (мы часто говорим о контейнере DI):
class App {
void main() { DI.getHighLevelObject().doStuff(); }
}
Обратите внимание, что существуют различные формы инъекций .Также обратите внимание, что с этой точки зрения внедрение сеттера может рассматриваться как форма обратного вызова - контейнер DI создает объект, а затем вызывает метод сеттера.Поток управления эффективно инвертирован.
4.АОП
Строго говоря, АОП имеет мало общего с тремя предыдущими пунктами.Оригинальный документ по AOP является очень общим и представляет идею объединения различных источников (возможно, выраженных на разных языках) для создания работающего программного обеспечения.
Я не буду больше углубляться в АОП.Что здесь важно, так это то, что внедрение зависимостей и AOP эффективно взаимодействуют друг с другом, потому что это делает переплетение очень простым.Если контейнер IoC и внедрение зависимостей используются для абстрагирования создания объектов, контейнер IoC можно легко использовать для создания аспектов перед внедрением зависимостей.В противном случае это потребует специальной компиляции или специального ClassLoader
.
Надеюсь, это поможет.