Подтвердить что ты не робот

Что может сделать АОП, что ООП не может сделать?

Я прежде всего разработчик 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 для определенных типов проблем.

4b9b3361

Ответ 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

В общем, весь вопрос о форме "Что может сделать это не так?" не имеют смысла. Все языки общего назначения одинаково сильны (см.: Церковная диссертация).

Различие между языками заключается не в том, что они могут делать, а в том, как они это делают. Другими словами, сколько работы вам нужно сделать, чтобы получить какое-то поведение на одном языке, а также то, как много работы для получения такого же поведения на каком-то другом языке.

Ответ 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 следует использовать экономно (что не является проблемой, поскольку число межсекторальных проблем в проекте, как правило, довольно мала).

и может очень затруднить отладку объектно-ориентированного кода, который он затрагивает.

Как так? Я не вижу проблемы, но если бы вы описали ее, я, вероятно, мог бы рассказать вам, как я ее решаю/избегаю.

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

Любая технология может использоваться плохо. Важно то, как тяжело это использовать, и что мы можем сделать, если мы это сделаем.