.
В вычислениях, аспектно-ориентированном программировании (AOP ) - это парадигма программирования, которая направлена на повышение модульности, позволяя разделить сквозные проблемы. Это достигается путем добавления дополнительного поведения к существующему коду (advice ) без изменения самого кода, вместо этого отдельно указывается, какой код изменяется с помощью спецификации «pointcut », например «log все вызовы функций, когда имя функции начинается с 'set' ". Это позволяет добавлять в программу поведение, которое не является центральным для бизнес-логики (например, ведение журнала), не загромождая код, являющийся основным для функциональности. АОП составляет основу аспектно-ориентированной разработки программного обеспечения..
АОП включает в себя методы и инструменты программирования, которые поддерживают модульность задач на уровне исходного кода, в то время как «аспектно-ориентированная разработка программного обеспечения» относится ко всей инженерной дисциплине.
Аспектно-ориентированное программирование влечет за собой разбиение логики программы на отдельные части (так называемые задачи, связанные функциональные области). Практически все парадигмы программирования поддерживают некоторый уровень группировки и инкапсуляции проблем в отдельные независимые сущности путем предоставления абстракций (например, функций, процедур, модулей, классов, методов), которые могут использоваться для реализации, абстрагирования и компоновки. эти проблемы. Некоторые проблемы «пересекают» несколько абстракций в программе и бросают вызов этим формам реализации. Эти проблемы называются сквозными или горизонтальными.
Ведение журнала иллюстрирует сквозную проблему, поскольку стратегия ведения журнала обязательно влияет на каждую регистрируемую часть системы. Таким образом, ведение журнала пересекает все зарегистрированные классы и методы.
Все реализации АОП имеют несколько пересекающихся выражений, которые инкапсулируют каждую проблему в одном месте. Разница между реализациями заключается в мощности, безопасности и удобстве использования предоставленных конструкций. Например, перехватчики, которые определяют методы для выражения ограниченной формы пересечения, без особой поддержки безопасности типов или отладки. AspectJ имеет ряд таких выражений и инкапсулирует их в специальный класс, аспект . Например, аспект может изменить поведение базового кода (не аспектная часть программы), применяя advice (дополнительное поведение) в различных точках соединения (точки в программа), указанный в количественной оценке или запросе, называемом pointcut (который определяет, совпадает ли данная точка соединения). Аспект также может вносить бинарно-совместимые структурные изменения в другие классы, такие как добавление членов или родителей.
AOP имеет несколько прямых предшественников A1 и A2: отражение и протоколы метаобъектов, тема -ориентированное программирование, фильтры композиции и адаптивное программирование.
Грегор Кичалес и его коллеги из Xerox PARC разработали явную концепцию АОП, а затем разработали AspectJ Расширение АОП для Java. Исследовательская группа IBM предпочла инструментальный подход к языковому дизайну и в 2001 году предложила Hyper / J и Concern Manipulation Environment, которые не получили широкого распространения.
В примерах в этой статье используется AspectJ.
Microsoft Transaction Server считается первым крупным приложением AOP, за которым следует Enterprise JavaBeans.
Как правило, аспект разбросан или запутан как код, что затрудняет его понимание и поддержку. Он разбросан из-за того, что функция (например, ведение журнала) распределена по ряду несвязанных функций, которые могут использовать его функцию, возможно, в совершенно несвязанных системах, на разных исходных языках и т. Д. Это означает, что для изменения ведения журнала может потребоваться изменение всех затронутых модулей. Аспекты запутываются не только с основной функцией систем, в которых они выражены, но и друг с другом. Это означает, что изменение одной проблемы влечет за собой понимание всех запутанных проблем или наличие некоторых средств, с помощью которых можно сделать вывод о последствиях изменений.
Например, рассмотрим банковское приложение с концептуально очень простым методом перевода суммы с одного аккаунта на другой:
недействительный перевод (аккаунт fromAcc, Account toAcc, int amount) выдает исключение {if (fromAcc.getBalance () < amount) throw new InsufficientFundsException(); fromAcc.withdraw(amount); toAcc.deposit(amount); }
Однако этот метод передачи игнорирует некоторые соображения, которые потребуются развернутому приложению: в нем отсутствуют проверки безопасности, чтобы убедиться, что текущий пользователь имеет разрешение на выполнение этой операции; транзакция базы данных должна инкапсулируйте операцию, чтобы предотвратить случайную потерю данных; для диагностики операция должна регистрироваться в системном журнале и т. д.
Версия со всеми этими новыми проблемами, например, может выглядеть примерно так: это:
void transfer (Account fromAcc, Account toAcc, int amount, User user, Logger logger, Database database) выдает исключение {logger.info ("Перевод денег..."); if (! isUserAuthorised (user, fromAcc)) {logger.info ("У пользователя нет разрешения."); выбросить новое исключение UnauthorisedUserException (); } if (fromAcc.getBalance () < amount) { logger.info("Insufficient funds."); throw new InsufficientFundsException(); } fromAcc.withdraw(amount); toAcc.deposit(amount); database.commitChanges(); // Atomic operation. logger.info("Transaction successful."); }
В этом примере другие интересы оказались запутанными с базовой функциональностью (иногда называемой проблемой бизнес-логики). Транзакции, безопасность и ведение журнала - все это иллюстрирует сквозные проблемы.
Теперь подумайте, что произойдет, если нам вдруг понадобится изменить (например) меры безопасности для приложения. В текущей версии программы операции, связанные с безопасностью, разбросаны по многочисленным методам, и такое изменение потребует значительных усилий.
АОП пытается решить эту проблему, позволяя программисту выражать сквозные проблемы в автономных модулях, называемых аспектами. Аспекты могут содержать рекомендации (код, соединенный с указанными точками в программе) и межтиповые объявления (добавленные структурные элементы к другим классам). Например, модуль безопасности может включать совет, который выполняет проверку безопасности перед доступом к банковскому счету. pointcut определяет время (точек соединения ), когда можно принять ss банковский счет, а код в теле совета определяет, как выполняется проверка безопасности. Таким образом, и чек, и места могут храниться в одном месте. Кроме того, хороший pointcut может предвидеть последующие изменения программы, поэтому, если другой разработчик создаст новый метод для доступа к банковскому счету, совет будет применяться к новому методу при его выполнении.
Итак, для приведенного выше примера реализации регистрации в аспекте:
аспект Logger {void Bank.transfer (Account fromAcc, Account toAcc, int amount, User user, Logger logger) {logger.info ("Передача Деньги..."); } void Bank.getMoneyBack (User user, int transactionId, Logger logger) {logger.info ("Пользователь запросил возврат денег."); } // Другой перекрестный код. }
Можно думать об АОП как об инструменте отладки или как об инструменте пользовательского уровня. Совет следует зарезервировать для случаев, когда вы не можете изменить функцию (на уровне пользователя) или не хотите изменять функцию в производственном коде (отладка).
Связанный с советами компонент аспектно-ориентированного языка определяет модель точки соединения (JPM). JPM определяет три вещи:
Модели точек соединения можно сравнивать на основе представленных точек соединения, способа задания точек соединения, операций, разрешенных в точках соединения, и структурных улучшения, которые можно выразить.
«Родственные» PCD соответствуют определенному типу точки соединения (например, выполнение метода) и имеют тенденцию принимать в качестве входных данных сигнатуру, подобную Java. Один из таких pointcut выглядит так:
execution (* set * (*))
Этот pointcut соответствует точке соединения метода и выполнения, если имя метода начинается с «set
"и есть ровно один аргумент любого типа.
«Динамические» PCD проверяют типы времени выполнения и связывают переменные. Например,
this (Point)
Этот pointcut соответствует, когда текущий выполняемый объект является экземпляром класса Point
. Обратите внимание, что неполное имя класса можно использовать с помощью обычного поиска типа Java.
PCD «области действия» ограничивают лексическую область действия точки соединения. Например:
внутри (com.company. *)
Этот pointcut соответствует любой точке соединения любого типа в пакете com.company
. *
- это одна из форм подстановочных знаков, которые можно использовать для сопоставления многих вещей с помощью одной подписи.
Pointcut может быть составлен и назван для повторного использования. Например:
pointcut set (): execute (* set * (*)) this (Point) within (com.company. *);Этот pointcut соответствует точке соединения метода и выполнения, если имя метода начинается с «
set
» и этот
является экземпляром типа Point
в пакете com.company
. На него можно ссылаться с помощью имени «set ()
".set ()
pointcut соответствует точке соединения, запустите код Display.update ()
после завершения точки соединения. "Существуют и другие типы JPM. Все языки рекомендаций могут быть определены в терминах их JPM. Например, гипотетический язык аспектов для UML может иметь следующий JPM:
Межтиповые объявления обеспечивают способ выразить сквозные проблемы, влияющие на структуру модулей. Также известный как открытые классы и методы расширения, это позволяет программистам объявлять в одном месте членов или родителей другого класса, обычно для того, чтобы объединить весь код, связанный с проблемой, в одном аспекте. Например, если программист реализовал проблему сквозного отображения-обновления с использованием вместо этого посетителей, межтиповое объявление с использованием шаблона посетителя может выглядеть в AspectJ следующим образом:
аспект DisplayUpdate {void Point.acceptVisitor ( Посетитель v) {v.visit (это); } // другой перекрестный код...}
Этот фрагмент кода добавляет метод acceptVisitor
к классу Point
.
Требуется, чтобы любые структурные дополнения были совместимы с исходным классом, чтобы клиенты существующего класса продолжали работать, если только реализация АОП не может рассчитывать на постоянное управление всеми клиентами.
Программы АОП могут влиять на другие программы двумя разными способами, в зависимости от основных языков и сред:
Сложность изменения среды означает, что большинство реализаций создают совместимые комбинированные программы посредством процесса, известного как переплетение случай преобразования программы. Ткач аспектов считывает аспектно-ориентированный код и генерирует соответствующий объектно-ориентированный код с интегрированными аспектами. Один и тот же язык АОП может быть реализован с помощью множества методов переплетения, поэтому семантику языка никогда не следует понимать в терминах реализации переплетения. Только скорость реализации и простота развертывания зависят от того, какой метод комбинирования используется.
Системы могут реализовать переплетение на уровне исходного кода с помощью препроцессоров (поскольку C ++ изначально был реализован в CFront ), которым требуется доступ к исходным файлам программы. Однако четко определенная двоичная форма Java позволяет ткачам байт-кода работать с любой программой Java в форме файла.class. Ткачи байт-кода могут быть развернуты во время процесса сборки или, если модель плетения для каждого класса, во время загрузки класса. AspectJ начался с переплетения на уровне исходного кода в 2001 году, предоставил ткацкий механизм байт-кода для каждого класса в 2002 году и предложил расширенную поддержку времени загрузки после интеграции AspectWerkz в 2005 году.
Любое решение, объединяющее программы во время выполнения, должно предоставлять представления, которые должным образом разделяют их, чтобы поддерживать раздельную модель программиста. Поддержка байт-кода Java для нескольких исходных файлов позволяет любому отладчику пройти через правильно сплетенный файл.class в редакторе исходного кода. Однако некоторые сторонние декомпиляторы не могут обрабатывать сплетенный код, потому что они ожидают код, созданный Javac, а не все поддерживаемые формы байт-кода (см. Также § Критика ниже).
ткачество предлагает другой подход. Это в основном подразумевает постобработку, но вместо исправления сгенерированного кода этот подход ткачества подклассирует существующие классы, так что модификации вводятся путем переопределения метода. Существующие классы остаются нетронутыми даже во время выполнения, и все существующие инструменты (отладчики, профилировщики и т. Д.) Могут использоваться во время разработки. Подобный подход уже зарекомендовал себя при реализации многих серверов приложений Java EE, таких как IBM WebSphere.
Стандартная терминология. используемые в Аспектно-ориентированном программировании могут включать:
Аспекты возникли из объектно-ориентированного программирования и вычислительное отражение. Языки АОП имеют функции, аналогичные, но более ограниченные, чем протоколы метаобъектов. Аспекты тесно связаны с такими концепциями программирования, как темы, миксины и делегирование. Другие способы использования парадигм аспектно-ориентированного программирования включают подход Composition Filters и подход hyperslices. По крайней мере, с 1970-х годов разработчики использовали формы перехвата и диспетчеризации, которые напоминают некоторые методы реализации АОП, но у них никогда не было семантики, которую обеспечивают сквозные спецификации, написанные в одном месте.
Дизайнеры рассмотрели альтернативные способы достижения разделения кода, такие как частичные типы C #, но в таких подходах отсутствует механизм количественной оценки, который позволяет достичь нескольких точек соединения кода с помощью одного декларативного оператора.
Хотя это может показаться несвязанным, при тестировании использование имитаторов или заглушек требует использования методов АОП, таких как советы и т. Д. Здесь взаимодействующие объекты предназначены для целей теста, сквозной проблемы. Таким образом, различные фреймворки Mock Object предоставляют эти функции. Например, процесс вызывает службу для получения суммы баланса. При тестировании процесса, откуда берется сумма, неважно, только то, что процесс использует баланс в соответствии с требованиями.
Программисты должны уметь читать код и понимать, что происходит, чтобы предотвратить ошибки. Даже при надлежащем образовании понимание сквозных проблем может быть затруднено без надлежащей поддержки для визуализации как статической структуры, так и динамического потока программы. Начиная с 2002 года AspectJ начал предоставлять плагины IDE для поддержки визуализации пересекающихся проблем. Эти функции, а также поддержка кода аспекта и рефакторинг теперь стали обычным явлением.
Учитывая мощь АОП, если программист делает логическую ошибку при выражении пересечения, это может привести к массовому сбою программы. И наоборот, другой программист может изменить точки соединения в программе - например, переименовав или переместив методы - способами, которые автор аспектов не ожидал, с непредвиденными последствиями. Одно из преимуществ модульного построения перекрестных задач - это возможность одному программисту легко влиять на всю систему; в результате такие проблемы представляют собой конфликт ответственности двух или более разработчиков за конкретный сбой. Однако решение этих проблем может быть намного проще при наличии АОП, поскольку необходимо изменить только аспект, тогда как соответствующие проблемы без АОП могут быть гораздо более распространенными.
Самая основная критика эффекта АОП заключается в том, что поток управления затемнен, и что он не только хуже, чем сильно критикуемый GOTO, но и на самом деле очень похож на анекдот COME FROM. Невнимательность к приложению, которая является фундаментальной для многих определений АОП (в рассматриваемом коде нет указаний на то, что будет применен совет, который указан вместо этого в pointcut), означает, что совет не виден, в отличие от явного вызов метода. Например, сравните программу COME FROM:
5 INPUT X 10 PRINT 'Результат:' 15 PRINT X 20 COME FROM 10 25 X = X * X 30 RETURN
с фрагментом AOP с аналогичной семантикой:
main () {input x print (result (x))} input result (int x) {return x} around (int x): call (result (int)) args (x) {int temp = continue (x) return temp * temp}
Действительно, pointcut может зависеть от условий выполнения и, следовательно, не быть статически детерминированным. Это можно смягчить, но не решить, с помощью статического анализа и поддержки IDE, показывающих, какие советы потенциально подходят.
Общая критика состоит в том, что АОП стремится улучшить «как модульность, так и структуру кода», но некоторые возражают, что вместо этого он подрывает эти цели и препятствует «независимой разработке и пониманию программ». В частности, количественная оценка с помощью pointcut нарушает модульность: «в общем, нужно обладать знаниями всей программы, чтобы рассуждать о динамическом выполнении аспектно-ориентированной программы». Кроме того, хотя его цели (разделение комплексных проблем на модули) хорошо понятны, его фактическое определение неясно и четко не отличается от других хорошо зарекомендовавших себя методов. Сквозные проблемы потенциально пересекают друг друга, требуя некоторого механизма разрешения, такого как упорядочивание. Действительно, аспекты могут применяться сами по себе, что приводит к таким проблемам, как парадокс лжеца.
Техническая критика включает в себя то, что количественная оценка pointcut (определение того, где выполняются советы) «чрезвычайно чувствительна к изменениям в программе», что является известная как проблема хрупкого острия. Проблемы с pointcut считаются неразрешимыми: если заменить количественную оценку pointcut явными аннотациями, вместо этого будет получено атрибутивно-ориентированное программирование, которое является просто явным вызовом подпрограммы и страдает той же проблемой рассеивания, что и AOP. предназначен для решения.
Следующие языки программирования реализовали АОП внутри языка или в виде внешней библиотеки:
| journal =
()