Что такое AOP, Внедрение зависимости и Инверсия Управления на Простом английском языке

Я попытался понять AOP, Внедрение зависимости и Инверсию Управления связанные с Spring понятия, но у меня есть трудное время, понимая это.

Кто-либо может объяснить это на простом английском языке?

34
задан Sklivvz 21 September 2012 в 13:29
поделиться

3 ответа

Я понимаю ваше замешательство, и мне потребовалось некоторое время, чтобы понять, как эти концепции связаны друг с другом. Итак, вот мое (в некотором роде личное) объяснение всего этого:

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. Внедрение зависимостей

Теперь идет внедрение зависимостей.Для меня внедрение зависимостей = IoC + инверсия зависимостей :

  1. зависимости предоставляются извне, поэтому мы применяем принцип инверсии зависимостей
  2. контейнер устанавливает зависимости (не мы), поэтому мы говорим об инверсии управления

В приведенном выше примере внедрение зависимостей может быть выполнено, если контейнер используется для создания экземпляров объектов и автоматически вводит зависимость в конструктор (мы часто говорим о контейнере DI):

 class App {
     void main() {  DI.getHighLevelObject().doStuff(); }
 }

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

4. АОП

Строго говоря, АОП имеет мало общего с тремя предыдущими пунктами. Основополагающая статья по АОП носит очень общий характер и представляет идею объединения различных источников (возможно, выраженных на разных языках) для создания работающего программного обеспечения.

Я не буду больше рассказывать об АОП. Здесь важно то, что внедрение зависимостей и АОП эффективно сочетаются друг с другом, потому что это очень упрощает переплетение. Если контейнер IoC и внедрение зависимостей используются для абстрагирования от создания экземпляров объектов, контейнер IoC можно легко использовать для объединения аспектов перед внедрением зависимостей. В противном случае для этого потребовалась бы специальная компиляция или специальный ClassLoader .

Надеюсь, это поможет.

47
ответ дан 27 November 2019 в 16:46
поделиться

Инъекция зависимостей была очень хорошо объяснена в Как объяснить инъекцию зависимостей пятилетнему ребенку?:

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

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

AOP - Aspect Oriented Programming - в основном означает, что исходный текст, который вы пишете, изменяется вместе с другим кодом на основе правил, расположенных ЗДЕСЬ. Это означает, что вы можете, например, сказать: "В качестве первой строки каждого метода я хочу иметь 'log.debug("entering method()")' в центральном месте, и каждый метод, который вы компилируете с этим правилом, будет содержать эту строку". Аспект" - это название взгляда на код другими способами, а не просто от первой до последней исходной строки.

Инверсия управления в основном означает, что у вас нет центрального куска кода, управляющего всем (например, гигантский переключатель в main()), а есть множество кусков кода, которые "каким-то образом" вызываются. Эта тема обсуждается в Википедии: http://en.wikipedia.org/wiki/Inversion_of_control

10
ответ дан 27 November 2019 в 16:46
поделиться

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

Допустим, у нас есть веб-приложение, которое может делать много разных вещей. Мы могли бы создать это приложение разными способами, но один из них - создать класс, отвечающий за выполнение каждой из этих вещей. Нам нужно откуда-то вызывать и создавать эти классы. Один из вариантов - иметь большой основной класс, который создает по одной из этих служб, открывает сокет и передает вызовы этим службам по мере их поступления. К сожалению, мы создали класс бога, у которого есть способ слишком много логики и слишком много знает о том, как все в нашей программе работает. Если мы что-то изменим в нашей программе, нам, вероятно, придется изменить этот класс.

Кроме того, это сложно проверить. Мы не можем тестировать какой-либо класс изолированно, если он работает с непосредственным созданием экземпляров и вызовом других классов. Модульные тесты писать становится намного сложнее.

Чтобы обойти это, используйте инверсию управления. Мы говорим: «Хорошо, это классы обслуживания. Кто их устанавливает? Не я». Обычно каждый из них определяет интерфейс, например LoginService или BillingService. Может быть несколько реализаций этого интерфейса, но вашему приложению все равно. Он просто знает, что может запросить определенный вид услуги или услугу с определенным именем, и в ответ получит что-то хорошее.

Внедрение зависимостей позволяет нам связать все наши маленькие кусочки вместе.Классы имеют доступные поля, аргументы конструктора или методы установки, которые являются ссылками на другие компоненты, к которым им потребуется доступ. Это значительно упрощает модульное тестирование. Вы можете создать тестируемый объект, добавить к нему фиктивную или заглушку зависимости, а затем проверить, что объект ведет себя правильно изолированно.

Наше настоящее приложение представляет собой сложную мешанину из кусочков, которые нужно просто соединить вместе. Есть много способов сделать это, в том числе позволить приложению делать предположения («этому классу нужен UserService, есть ровно один другой класс, за который я отвечаю, который реализует UserService») или путем тщательного объяснения того, как они соединяются друг с другом в XML. или Java. Spring, по своей сути, - это сервис, который заботится о связывании этих классов вместе.

Теперь мы переходим к АОП. Допустим, у нас есть все эти классы, которые сложным образом связаны друг с другом. Есть некоторые общие проблемы, которые мы, возможно, захотим описать в очень общих чертах. Например, возможно, вы хотите запускать транзакцию базы данных всякий раз, когда вызывается какая-либо служба, и фиксировать эту транзакцию, пока служба не генерирует исключение. Оказывается, Spring находится в уникальном положении для выполнения такой задачи. Spring может создавать прокси-классы на лету, которые реализуют любой интерфейс, который нужен вашим классам, и может заключать ваш класс в свой прокси. Конечно, IoC и внедрение зависимостей не являются необходимыми для аспектно-ориентированного программирования, но это чрезвычайно удобный способ его выполнения.

1
ответ дан 27 November 2019 в 16:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: