Что может сделать АОП, что ООП не может сделать?
Я прежде всего разработчик Java. Я встретил довольно много разработчиков Java, которые любят АОП. В последнее время я вижу все больше и больше "шаблонов проектирования" АОП, которые, похоже, довольно широко приняты. Тем не менее, я все еще не уверен, что АОП в коде OO - хорошая идея в целом по нескольким причинам.
-
Он добавляет "волшебство" к коду в
формы непрозрачной сложности, которая может
быть чрезвычайно трудным для отладки и может
сделать его чрезвычайно трудным для отладки
объектно-ориентированный код, который он
влияет.
-
Мне кажется, в основном
ненужные и (что еще хуже) часто используются
чтобы избежать необходимости хорошо проектировать или
для компенсации прежних бедных
дизайн.
Вот пример, который я видел много за последние пару лет, в качестве фона для моего вопроса.
До AOP (из документов Hibernate)
public void saveMyEntityToTheDatabase(MyEntity entity) {
EntityTransaction tx = null;
try {
tx = entityManager.getTransaction();
tx.begin();
entityManager.persist(entity);
tx.commit();
} catch (RuntimeException e) {
if(tx != null && tx.isActive()) {
tx.rollback();
}
throw e;
}
}
После AOP
@Transactional
public void saveMyEntityToTheDatabase(MyEntity entity) {
entityManager.persist(entity);
}
Кажется, это очевидная победа для АОП для многих людей. Для меня исходная проблема является симптомом несогласованных уровней абстракции API. То есть, EntityManager
намного ниже, чем API-интерфейс бизнес-уровня сообщения, использующего его. Эта проблема может быть решена с более подходящим уровнем абстракции и лучшим (OO) дизайном.
Решение OO
public void saveMyEntityToTheDatabase(MyEntity entity) {
database.performInTransaction(new Save(entity));
}
Это решение предполагает, что объект database
содержит такую же транзакционную логику, что и тот аспект, который отвечает за методы @Transactional
. Это касается моих проблем выше, сделав более очевидным, что есть что-то, управляющее взаимодействием с EntityManager
, а не введение другой парадигмы программирования.
Итак, наконец, мой вопрос: что может AOP сделать, что ООП не может? Я немного уверен в его полезности в протоколе трассировки и, возможно, по умолчанию toString()
реализациях или чем-то подобном, но мне было бы интересно узнать, сможет ли кто-нибудь найти его значительно лучше, чем OO для определенных типов проблем.
Ответы
Ответ 1
Короткий ответ - ничто. АОП, хотя и добавляет щепотку того, что мы будем вспоминать в мои дни в американских морских пехотинцах, как FM, которые при очистке для гражданской аудитории означают "Волшебная магия". Вы правы, что абсолютно ничего не достигнуто в первом случае, который вы цитируете, что не достигается во втором. Я думаю, что главная причина движения - вопрос ясности и растущая мантра "Меньше церемоний" в кодексе. Таким образом, вы можете написать код для обработки транзакций или отказаться от церемонии с АОП, которую предоставляет поставщик, или контейнер, по-видимому, лучше проверен, чем код, который вы пишете вручную. Еще один момент в AOP заключается в том, что он может быть изменен в дескрипторах развертывания, Spring конфигурационных файлах и т.д., А затем может быть изменен, если ваши требования изменяются без каких-либо изменений в вашем фактическом коде. Таким образом, вы пишете дорогой код, который продолжает выражать бизнес-логику, которую вы имели в виду, оплачивается, а слой "FM" обрабатывает такие вещи, как транзакции, протоколирование и т.д. С либеральным разбрызгиванием пыли AOP pixie.
YMMV, конечно.
Ответ 2
AOP - OO; Аспекты - это объекты.
Я не понимаю, почему и/или менталитет.
AOP - идеальный выбор для цепных, сквозных проблем (например, протоколирование, безопасность, транзакции, удаленное проксирование и т.д.)
UPDATE:
Я думаю, что критика, предлагаемая ОП, субъективна и не столь широко распространена, как указано. Утверждения, заявленные без доказательства, могут быть отклонены без доказательств.
Я не верю в использование магии, но АОП не волшебство, если вы это понимаете. Я понимаю. Возможно, ОП не делает. Если это случай, и OP более удобен с решением OO, я бы сказал, иди за ним.
"Мне кажется, что это не нужно" - это просто мнение, предлагаемое без доказательств. На это нет ответа, кроме "Я не согласен".
Я думаю, что АОП идеально подходит для этих случаев, потому что я могу применить его декларативным образом. Я могу написать класс аспект один раз и применять его во многих местах с мелкозернистым управлением, изменяя его в конфигурации, а не в коде. Я могу выбрать, какие методы, классы и пакеты имеют аспект, применяемый к ним в конфигурации.
Попробуйте это с помощью ручного подхода OO.
Кроме того, АОП является объектно-ориентированным. Вы можете смотреть на него как на умного человека, который дает вам язык или структуру, специфичную для домена, за то, что вы хотите сделать вручную. Общие черты были абстрагированы во что-то более общее. Почему кто-то возражает против этого?
Ответ 3
Мне AOP является сокращением Шаблон перехватчика. И сам шаблон перехватчика выводится (или влияет или получает идею) из Template Method, AFAICS.
Популярным примером Interceptor
является Servlet Filter
. И мы знаем, что они очень полезны во многих случаях.
Так как все эти шаблоны полезны, следовательно, AOP, который получен из них, также полезен. И как вы сами указали несколько своих обычаев.
Ответ 4
В общем, весь вопрос о форме "Что может сделать это не так?" не имеют смысла. Все языки общего назначения одинаково сильны (см.: Церковная диссертация).
Различие между языками заключается не в том, что они могут делать, а в том, как они это делают. Другими словами, сколько работы вам нужно сделать, чтобы получить какое-то поведение на одном языке, а также то, как много работы для получения такого же поведения на каком-то другом языке.
Ответ 5
Аспектно-ориентированное программирование и объектно-ориентированное программирование
Ответ Mecki на AOP является эксклюзивным: -)
Ответ 6
Для меня до сих пор единственным прецедентом, для которого AOP определенно лучше, чем ООП, является трассировка вызова метода.
Ответ 7
У меня возникло несчастье работать в приложении, где вызовы служб выполнялись с использованием простого ООП. Я ненавидел это, и я собираюсь рассказать вам, почему:
Во-первых, ваш пример несколько упрощен, так как обычно граница транзакции связана не только с одним взаимодействием с базой данных, но и вокруг всего вызова бизнес-службы. Поэтому давайте в качестве примера рассмотрим следующий метод:
@Transactional
public Employee hire(Person p, Employee manager, BigDecimal salary) {
// implementation omitted
}
который вызывается с помощью
Employee hired = service.hire(candidate, manager, agreedOnSalary);
В вашем случае это станет следующим:
class HireAction implements Callable<Employee> {
private final Person person;
private final Employee manager;
private final BigDecimal salary;
public HireAction(Person person, Employee manager, BigDecimal salary) {
this.person = person;
this.manager = manager;
this.salary = salary;
}
@Override
public Employee call() throws Exception {
// implementation omitted
}
}
и вызывается
Employee hired = session.doInTransaction(new HireAction(candidate, manager, agreedOnSalary));
Конструктор необходим для обеспечения назначения всех параметров (поэтому компилятор может жаловаться, если параметр добавлен к методу без обновления вызывающего абонента).
Второй подход уступает по следующим причинам:
- Он нарушает DRY, поскольку каждый параметр упоминается 3 раза, а тип возврата - дважды. В частности, где вы помещаете JavaDoc для параметров? Вы тоже копируете это?
-
Сложно группировать связанные сервисные операции в службе и совместно использовать код. Да, вы можете поместить все связанные операции в один и тот же пакет и иметь общий суперкласс для совместного использования кода, но опять же это довольно многословно, что подход AOP просто помещает их в один класс. Или вы можете делать такие сумасшедшие вещи, как:
class HRService {
class HireAction {
// impl omitted
}
class FireAction {
// impl omitted
}
}
и вызывать его с помощью
Employee emp = session.doInTransaction(new HRService().new HireAction(candidate, manager, salary));
-
Программист-программист может забыть начать транзакцию:
Employee e = new HireAction(candidate, manager, salary).call();
или запустите транзакцию в неправильном сеансе/базе данных. Транзакции и бизнес-логика - это разные проблемы, обычно решаемые разными разработчиками и, следовательно, должны быть разделены.
Подводя итог, простой подход ООП является более подробным и подверженным ошибкам, что приводит к увеличению затрат во время разработки и обслуживания.
Наконец, о вашей критике АОП:
Он добавляет "волшебство" к коду в виде непрозрачной сложности, которая может быть чрезвычайно сложной для отладки,
Сложность всегда трудно отлаживать, независимо от происхождения. Я помню некоторые сеансы отладки с исходным кодом спящего режима, разумное использование шаблона команды заставило его не менее сложно найти код, который имел значение.
Наличие перехватчика AOP может быть неочевидным (хотя, если метод аннотирован @Transactional
, я бы счел его очевидным), поэтому AOP следует использовать экономно (что не является проблемой, поскольку число межсекторальных проблем в проекте, как правило, довольно мала).
и может очень затруднить отладку объектно-ориентированного кода, который он затрагивает.
Как так? Я не вижу проблемы, но если бы вы описали ее, я, вероятно, мог бы рассказать вам, как я ее решаю/избегаю.
Мне кажется, что в большинстве случаев это не нужно, и (что еще хуже) часто используется, чтобы избежать необходимости хорошо проектировать или компенсировать предыдущий плохой дизайн.
Любая технология может использоваться плохо. Важно то, как тяжело это использовать, и что мы можем сделать, если мы это сделаем.