Почему "против"? Это не "против". Вы можете использовать Аспектно-ориентированное программирование в сочетании с функциональным программированием, но также в сочетании с Объектно-ориентированным. Это не «против», это «Аспектно-ориентированное программирование с объектно-ориентированным программированием».
Для меня АОП - это своего рода «метапрограммирование». Все, что делает AOP, также может быть сделано без добавления кода. АОП просто спасает вас писать этот код.
В Википедии есть один из лучших примеров этого метапрограммирования. Предположим, у вас есть графический класс с множеством методов set ... (). После каждого метода установки данные графики менялись, поэтому графика менялась, и, следовательно, графика должна обновляться на экране. Предположим, что для перерисовки графики вы должны вызвать «Display.update ()». Классический подход состоит в том, чтобы решить эту проблему, добавив больше кода . В конце каждого метода набора вы пишете
void set...(...) {
:
:
Display.update();
}
Если у вас есть 3 set-метода, это не проблема. Если у вас есть 200 (гипотетически), становится больно добавлять это везде. Кроме того, всякий раз, когда вы добавляете новый метод set, вы должны быть уверены, что не забыли добавить его в конец, иначе вы просто создали ошибку.
АОП решает это без добавления тонны кода, вместо этого вы добавляете аспект:
after() : set() {
Display.update();
}
И это все! Вместо того, чтобы писать код обновления самостоятельно, вы просто сообщаете системе, что после достижения точки set () она должна запустить этот код и запустить этот код. Не нужно обновлять 200 методов, не нужно обязательно добавлять этот код в новый метод set. Кроме того, вам просто нужен pointcut:
pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);
Что это значит? Это означает, что если метод называется «set *» (* означает, что после set может следовать любое имя), независимо от того, что метод возвращает (первая звездочка) или какие параметры он принимает (третья звездочка), и это метод MyGraphicsClass, и это class является частью пакета "com.company. *", тогда это pointcut set (). И наш первый код говорит: « после запуска любого метода, который является заданным pointcut, запустите следующий код».
Посмотрите, как АОП элегантно решает проблему здесь? На самом деле все описанное здесь может быть сделано во время компиляции. Препроцессор AOP может просто изменить ваш источник (например, добавив Display.update () в конец каждого метода set-pointcut), прежде чем даже скомпилировать сам класс.
Тем не менее, этот пример также показывает один из больших недостатков АОП. AOP на самом деле делает то, что многие программисты считают « Anti-Pattern ». Точная схема называется « Действие на расстоянии ».
Действие на расстоянии - это антишаблон (общепризнанная распространенная ошибка), при котором поведение в одной части программы сильно меняется в зависимости от того, трудно или невозможно идентифицировать операции в другой части программы.
Как новичок в проекте, я мог бы просто прочитать код любого метода set и считать его неисправным, так как кажется, что он не обновляет отображение. Я не вижу просто глядя на код метода set, что после его выполнения какой-то другой код будет «магическим образом» выполняться для обновления отображения. Я считаю это серьезным недостатком! При внесении изменений в метод могут появиться странные ошибки. Дальнейшее понимание потока кода, в котором некоторые вещи работают правильно, но не очевидно (как я уже сказал, они просто волшебным образом работают ... как-то), действительно сложно.
Обновить
Просто чтобы прояснить это: у некоторых людей может сложиться впечатление, что я говорю, что АОП - это что-то плохое и не должно использоваться. Это не то, что я говорю! АОП на самом деле отличная особенность. Я просто говорю «Используйте это осторожно». AOP вызовет проблемы, только если вы смешаете обычный код и AOP для одного и того же аспекта . В приведенном выше примере у нас есть аспект обновления значений графического объекта и рисования обновленного объекта. Это на самом деле один аспект. Кодирование половины этого как нормального кода, а другая половина как аспекта - вот что добавляет проблему.
Если вы используете AOP для совершенно другого аспекта, например, для регистрации, вы не столкнетесь с проблемой анти-паттернов. В этом случае новичок в проекте может спросить: «Откуда берутся все эти сообщения журнала? Я не вижу никакого вывода журнала в коде», но это не большая проблема. Изменения, которые он вносит в программную логику, вряд ли сломают средство ведения журнала, а изменения, внесенные в средство ведения журнала, вряд ли нарушат его логику программы - эти аспекты полностью разделены. Преимущество использования AOP для ведения журнала заключается в том, что программный код может полностью сконцентрироваться на выполнении всего, что он должен делать, и вы все равно можете вести сложную запись в журнал, при этом ваш код не будет загроможден сотнями сообщений журнала повсюду. Кроме того, когда вводится новый код, сообщения с магическим журналом будут появляться в нужное время с нужным содержанием.
Таким образом, хорошим примером использования AOP в моем примере было бы всегда регистрировать, если какое-либо значение было обновлено с помощью метода set. Это не создаст анти-паттерн и вряд ли когда-либо станет причиной каких-либо проблем.
Кто-то может сказать, что если вы можете легко злоупотреблять AOP, создавая так много проблем, плохая идея использовать все это. Однако какой технологией нельзя злоупотреблять? Вы можете злоупотреблять инкапсуляцией данных, вы можете злоупотреблять наследованием. Практически все полезные технологии программирования могут быть использованы неправильно. Рассмотрим язык программирования настолько ограниченный, что он содержит только те функции, которыми нельзя злоупотреблять; язык, на котором функции могут использоваться только так, как они изначально были предназначены для использования. Такой язык будет настолько ограничен, что спорно, если он может быть даже использовать для реального мира программирования.