Определенные проблемы решаются более элегантно с АОП?

19

Я столкнулся с идеей Аспектно-ориентированного программирования, и у меня есть некоторые проблемы с этим.

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

Но реализация АОП, по-видимому, заключается в модификации кода извне модуля. Так, например, можно написать аспект, который меняет то, что происходит, когда конкретный объект передается в качестве параметра в функцию. Это, кажется, идет вразрез с идеей модулей. Я не должен быть в состоянии изменить поведение модуля извне этого модуля, иначе весь смысл модулей перевернут. Но аспекты, кажется, делают именно это!

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

Является ли АОП хорошей практикой? Определенные проблемы программирования решаются более элегантно с помощью AOP?

Уинстон Эверт
источник
аааа, знаменитый обезьяний патч!
Муад Диб
1
Я отредактировал вопрос, чтобы улучшить его тон, и проголосовал за его возобновление.
Роберт Харви
Questio также был переспрошен в другой форме здесь: programmers.stackexchange.com/questions/19344/…
Питер Боутон,

Ответы:

19

Аспектно-ориентированное программирование позволяет выполнять определенные типы программирования, которые трудно выполнить без ненужного разброса кода по всему приложению или библиотеке, не связанной с основными функциями вашего программного обеспечения (т. Е. Сквозными задачами). Примеры включают в себя:

  1. Регистрация и мониторинг
  2. Анализ производительности
  3. Отладка и трассировка
  4. Отменить функциональность
  5. Проверка входов и выходов
  6. Изменяет поведение существующих объектов
  7. Фильтры объектов
  8. Реализация безопасности
  9. Управление транзакциями

Ограничивая такие сквозные задачи одной частью приложения, а затем ссылаясь на эти функции в коде через атрибуты, перехват вызовов методов или динамические прокси, вы разрешаете инкапсуляцию сквозного поведения; Это дает все преимущества (то есть, единую точку модификации) инкапсуляции в любом другом месте вашего приложения.

Ключевым моментом здесь является то, что AOP инкапсулирует поведение, которое является 1) общим для всего приложения и 2) периферийным по отношению к основной функциональности приложения.

Роберт Харви
источник
7

Я опаздываю к игре, но я предоставляю это для будущих разработчиков, которые могут наткнуться на этот вопрос.

Я бы настоятельно рекомендовал против AOP, если ваше приложение зависит от его правильной работы. Аспекты работают так:

  • Совет (дополнительное поведение) применяется к
  • Точки соединения (места, где можно прикрепить дополнительный код, например, начало или конец метода или когда срабатывает данное событие)
  • ... где pointcut (шаблон, который определяет, соответствует ли данная точка соединения) шаблоны

Для тех, кто давно занимается компьютерами, тот факт, что шаблоны используются, может быть чем-то, на что стоит обратить пристальное внимание. Итак, вот пример pointcut, который соответствует любому методу с именем setнезависимо от аргументов:

call(* set(..))

Так что это довольно широкая точка отсчета, и должно быть ясно, что рекомендуется обращаться с этим осторожно (не каламбур), потому что вы применяете советы ко многим вещам.

Или, чёрт возьми, давайте применять советы ко всему , независимо от имени или подписи!

execution(* *(..))

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

Итак, вот что выглядит как относительно безопасный pointcut:

pointcut setter(): target(Point) &&
                   ( call(void setX(int)) ||
                     call(void setY(int)) );

Это явно дает совет, если найдены методы с именем setXили setYдля Pointобъекта. Методы могут только получать ints, и они должны быть void. Выглядит довольно безопасно, верно? Ну, это безопасно, если эти методы существуют, и вы применили правильный совет. Если нет, то тоже плохо; это молча терпит неудачу.

В качестве примера, друг пытался отладить Java-приложение, в котором время от времени все возвращали неверные данные. Это был нечастый сбой, и, похоже, он не коррелировал с каким-либо конкретным событием или данными в частности. Это была многопоточная ошибка, которую сложно проверить или обнаружить. Оказывается, они использовали аспекты, чтобы заблокировать методы и сделать их «потокобезопасными», но программист переименовал метод, и pointcut не смог сопоставить его, что привело к тихой поломке приложения.

Таким образом, я говорю людям, что если они должны использовать AOP для обработки таких аспектов, как исключения: в хорошо спроектированной системе, и если ничего не происходит, их можно удалить, и программное обеспечение по-прежнему функционирует правильно. Однако, если функциональность программы зависит от АОП, вы вводите хрупкость в вашу программу, которая неоправданна.

Таким образом, ведение журнала, отладка и трассировка являются отличными примерами поведения, которое идеально подходит для аспектов, но для безопасности? Нет. Поток безопасности? Нет.

Для надежной альтернативы АОП см. Черты . Вместо того, чтобы привязываться к языку, они напрямую интегрируются в него, не нуждаются в IDE «с учетом особенностей» (хотя это может помочь) и имеют сбои во время компиляции, если требуемые методы отсутствуют. Черты намного лучше справляются с разделением интересов, потому что проблема была лучше определена с самого начала. Я использую их широко, и они фантастические.

Кертис По
источник
Вместо того, чтобы утверждать, что AOP не следует использовать для основной функциональности, может быть более уместно сказать, что pointcut, которые зависят от имен методов, являются плохой идеей. Вероятно, я бы поспорил, что блокировка и синхронизация не являются хорошими вариантами использования для АОП.
Код Блинг
2

Единственная ситуация, в которой AOP может быть единственным приемлемым и практичным решением, - это когда у вас нет доступа к исходному коду . Чтобы использовать утомленный старый пример сквозного концерна Logging:

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

И если вы все равно создаете аспект ведения журнала, вы также можете рассмотреть возможность ведения журнала с помощью AOP через собственный код.

Джозеф Таненбаум
источник
Ведение журнала для "интересных" вещей. Как вы можете сделать что-то еще, кроме «входа с этими параметрами» и «выхода» с ведением журнала AOP?
@Thorbjorn: ведение журнала / отладка / трассировка - это только одна из многих областей функциональности, с которыми может помочь AOP. Я использовал это в качестве примера, чтобы проиллюстрировать свою точку зрения. Я пытаюсь подчеркнуть, что AOP дает вам больший контроль над сторонним байт-кодом.
Джозеф Таненбаум
конечно, но я действительно хотел знать, может ли логирование AOP сделать больше, чем просто логирование входа-выхода?
Это зависит от того, какой инструмент АОП вы используете, но, безусловно, существуют ограничения на то, что вы можете сделать. Вполне может быть невозможно выйти за пределы входа-выхода.
Джозеф Таненбаум