Аспектно-ориентированное программирование: различия между версиями

Содержимое удалено Содержимое добавлено
викификация
Строка 1:
{{wikipedia|Аспектно-ориентированное программирование}}
 
'''Аспе́ктно-ориенти́рованное программи́рование''' (в дальнейшем АОП) — это методика программирования в рамках [[Объектно:w:ru:Класс-ориентированное программирование|классовой парадигмы]], основанная на понятии ''[[:w:ru:Аспект|аспекта]]'' — [[:w:ru:Блок (программирование)|блока]] кода, инкапсулирующего [[сквозное:w:ru:Инкапсуляция поведение(программирование)|инкапсулирующего]] сквозное поведение в составе [[:w:ru:Класс (программирование)|классов]] и повторно используемых [[:w:ru:Модуль (программирование)|модулей]].
 
== История ==
 
Аспектно-ориентированное программированиеАОП выросло из осознания того, что в типовых программах на [[:w:ru:Объектно-ориентированный язык программирования|объектно-ориентированных языках]] часто представлено поведение, которое не вмещается естественно в один или даже в несколько тесно связанных программных модулей. Пионеры аспектного подхода ввели термин «пересечение» (''crosscutting'') для обозначения поведения кода, при котором пересекаются ответственности разработчиков программных модулей. В объектно-ориентированном программировании, например, единицей модульности является класс, а «секущее» свойство охватывает несколько классов. Часто пересечение встречается при организации журналирования приложений, контекстно зависимой [[:w:ru:Обработка исключений|обработке ошибок]], оптимизации выполнения программ, а также в [[:w:ru:Шаблон проектирования|шаблонах проектирования]].
 
Если вы когда-нибудь работали над кодом со сквозной функциональностью, вам известны проблемы, связанные с ограничением модульности. Поскольку «поперечное» поведение реализуется разрозненно, разработчики находят такое поведение затруднительным в осмысливании, реализации и изменении. Код для ведения журналов, например, переплетается с кодом, отвечающим в основном за что-либо другое. В зависимости от масштаба и сложности crosscutting-отношения степень запутанности может быть более или менее значительной.
Строка 15 ⟶ 16 :
AOП дополняет объектно-ориентированное программирование, обогащая его другим типом модульности, который позволяет локализовать код реализации crosscutting логики в одном модуле. Такие модули обозначаются термином аспекты, от аспектно-ориентированного программирования. За счет отделения аспектно-ориентированного кода работа с crosscutting- отношениями упрощается. Аспекты в системе могут изменяться, вставляться, удаляться на этапе компиляции и, более того, повторно использоваться.
 
== AspectJ ==
 
[[w:AspectJ|AspectJ]] — аспектно-ориентированное расширение языка [[w:Java|Java]], предложенное [[w:Xerox PARC|Xerox PARC]]. Представим его на примере программы для журналирования событий, реализованной на AspectJ. Этот пример взят из системы с открытым кодом Cactus, упрощающей тестирование Java-компонентов на стороне сервера. Каркас Cactus разработан для поддержки процесса отладки с помощью трассировки вызовов всех методов. Версия 1.2 Cactus была написана без [[w:AspectJ|AspectJ]]. Поэтому большинство методов выглядели, как показано ниже.
 
<source lang="java">
Строка 51 ⟶ 53 :
</source>
 
Проанализируем этот пример и посмотрим, какие действия осуществляет аспект. Первое, на что нужно обратить внимание — это объявление аспекта. Оно подобно [[:w:|объявлению класса]] и, так же как класс, определяет тип Java. Кроме того, аспект содержит конструкции ''pointcut'' и ''advice''.
 
=== Конструкция ''pointcut'' и точки соединения ===
Прежде всего, рассмотрим, что представляет собой '''join point''' ({{lang-ru|точка соединения}}). Точки соединения — это однозначно определенные точки при выполнении программы. Так под точками соединения в AspectJ подразумеваются: вызовы [[:w:ru:Метод (языки программирования)|методов]], точки обращения к членам класса и исполнение блоков [[:w:ru:Обработка исключений|обработчиков исключений]] и т. д. Точки соединения могут, в свою очередь, содержать другие точки соединения. Например, результат вызова метода может передаваться каким-то другим методам. А pointcut является языковой конструкцией, которая отбирает множество точек соединения на основании определенного критерия. В приведенном выше примере первый pointcut под именем <code>publicMethods</code> выбирает исполнения всех <code>public</code> методов в пакете org.apache.cactus. Подобно int,тому которыйкак <code>int</code> является базовым типом Java, так <code>Execution</code> является базовым pointcut. Он выбирает исполнения методов, соответствующих сигнатуре, заданной в скобках. Для сигнатур допустимо включение символов шаблонов: в приведенном примере оба pointcut-а содержат несколько таких символов. Второй pointcut с именем <code>logObjectCalls</code> выбирает все исполнения методов в классе Logger. Третий pointcut — <code>loggableCalls,</code> — объединяет два предыдущих, используя <code>&& !</code>, что означает выбор всех public методов из org.apache.cactus за исключением таковых в классе Logger. (Регистрация log методов привела бы в результате к бесконечной рекурсии).
 
=== Конструкция advice ===
Строка 66 ⟶ 68 :
</source>
 
Этот advice использует класс <code>Logger</code>, методы <code>entry</code> и <code>exit</code> которого выглядят следующим образом:
 
<source lang="java">
Строка 75 ⟶ 77 :
</source>
 
В приведенном примере классу <code>logger</code> передается String, образованная от <code>thisJoinPoint</code>, специального объекта, разрешающего доступ к контексту времени выполнения, в котором исполняется точка соединения. В данном, используемом Cactus-ом аспекте, advice применяет этот объект для извлечения параметров метода, передающихся в каждый зарегистрированный вызов метода. «След» вызова метода (с применением аспекта) в log-файле выглядит следующим образом:
 
<pre>
Строка 85 ⟶ 87 :
 
=== Advice типа around ===
В примере Cactus определены advice типа <code>before()</code> и <code>after()</code>.
Advice третьего типа <code>around()</code> дает возможность разработчику аспектов управлять передачей управления на точку соединения. При этом используется специальный синтаксис <code>proceed()</code>.
Следующий advice вызывает (или не вызывает) исполнение метода <code>say</code> из класса <code>Hello</code> в зависимости от генерируемого случайного числа (random):
 
<source lang="java">
Строка 104 ⟶ 106 :
 
=== Программирование в AspectJ ===
Теперь, когда мы представляем себе, что такое код аспекта, зададим вопрос: «Как заставить приведенный выше код работать?».
 
Чтобы аспекты могли оказывать воздействие на обычный, основанный на классах код, эти аспекты должны быть «вплетены» в модифицируемый ими код. Чтобы осуществить это в AspectJ, надо [[:w:ru:Компилятор|откомпилировать]] код класса и аспекта ajc-компилятором. ajc может функционировать как полноценный компилятор, генерируя действующий код класса, так и как [[:w:ru:препроцессор|препроцессор]], генерируя .java файлы компилируемые стандартными средствами Java (со ссылкой на небольшой run-time JAR).
 
Для компиляции в AspectJ необходимо явно задать исходные файлы (и для аспектов, и для классов), подлежащие включению в данную компиляцию — ajc не использует classpath, в отличие от javac. Это имеет определенный смысл, поскольку каждый класс стандартного приложения Java является, в некотором смысле, изолированным [[:w:ru:Компонент (программирование)|компонентом]]. Для корректной работы классу требуется всего лишь присутствие других классов, на которые он ссылается. Аспекты же представляют совокупное поведение, перекрывающее множество классов. Поэтому AOPАОП-приложение должно компилироваться, как модуль, а не по одному классу за один раз.
 
Задавая файлы для компиляции, можно также включать и отключать различные аспекты системы на этапе компиляции. Например, включая или исключая описанный ранее аспект для регистрации, разработчик приложения может добавлять или удалять трассировку метода системы Cactus.
Существенное ограничение '''текущей версии''' AspectJ состоит в том, что ее компилятор может вводить аспекты только в код, для которого есть исходный текст. Иными словами, невозможно использовать ajc для включения advice в уже откомпилированные классы. Разработчики AspectJ представляют это ограничение как временное, и на Web-сайте AspectJ можно найти подтверждение того, что в будущей версия (официально — версия 2.0) будут допустимы модификации на уровне [[:w:ru:Байт-код|байт-кода]].
 
=== Обзор возможностей AspectJ ===
Строка 143 ⟶ 145 :
===== Наследование в стиле mix-in =====
AspectJ позволяет добавлять члены в интерфейсы (аналогично добавлению в классы), что относится к наследованию в стиле mix-in a la C++.
Если мы хотим ввести в общее употребление аспект, рассмотренный в предыдущем разделе, таким образом, чтобы стало возможным многократное использование кода <code>timestamp</code> для множества объектов, следует определить интерфейс с именем ''<code>TimestampedObject''</code>, и далее использовать ''<code>introduction''</code> для добавления тех же самых членов и переменных в интерфейс вместо конкретного класса:
 
<source lang="java">
Строка 172 ⟶ 174 :
<source lang="java">declare parents: ValueObject||BigValueObject implements TimestampedObject;</source>
 
После того как определены операции, поддерживаемые интерфейсом ''<code>TimestampedObject''</code>, можно использовать ''pointcut''-ы и ''advice'' для автоматического обновления меток времени (timestamp) при возникновении подходящих условий. Так, дополнение к ''Timestamp'', показанное ниже, регистрирует время каждого вызова ''setter'' метода:
 
<source lang="java">
Строка 186 ⟶ 188 :
</source>
 
Заметьте, что ''pointcut'' определяет аргументы, используемые в ''advice'' типа ''after()'' — в данном случае, это ''<code>TimestampedObject''</code>, имеющий метод установки <code>set</code>.
''Pointcut this()'' определяет все точки соединения, где исполняемый в настоящее время объект имеет тип, заданный в скобках. Несколько других типов значений могут быть связаны с аргументами advice, такие как аргументы метода, исключения при исполнении метода и результат вызова метода.
 
Строка 204 ⟶ 206 :
 
==== Обработка ошибок ====
Есть множество [[:w:ru:Обработка исключений|обрабатываемых исключений]] в языке [[w:ru:Java|Java]]. Зачастую создаются такие методы, которые наверняка не должны вызывать исключений, и, возможно, они не будут происходить ни у кого из потенциальных пользователей метода. Мы не призываем игнорировать возможные исключения, но тяжело отслеживать присутствие исключений во всех вызовах метода. Есть разные искусные способы использования блоков try/catch, чтобы все-таки решить эту задачу, но самый элегантный — это declare soft в AspectJ. Рассмотрим пример работы с базой данных:
 
<source lang="java">
Строка 225 ⟶ 227 :
}</source>
 
Если не использовать AspectJ или объявлять исключение в каждой сигнатуре метода, то пришлось бы встраивать блоки try/catch для обработки <code>SQLException</code>, генерируемого почти каждым методом [[w:Java Database Connectivity|JDBC]] [[w:Интерфейс программирования приложений|API]]. Язык [[w:AspectJ|AspectJ]] позволяет использовать следующий внутренний аспект, чтобы автоматически транслировать все <code>SQLException</code> в <code>org.aspectj.lang.SoftException</code>.
 
<source lang="java">
Строка 253 ⟶ 255 :
 
=== Инструментальная поддержка ===
Xerox подготовил [[w:AspectJAsprctJ|AspectJ]] к использованию под '''[[w:Mozilla Public License|Mozilla Public License]]''', что является хорошей новостью для энтузиастов [[w:Открытый исходный код|открытого кода]]. Это обрадует и тех, кто собирается остановить свой выбор на AspectJ в ближайшем будущем, поскольку продукт ничего не стоит, и при этом для пользователя сохраняется гарантированная возможность проверки исходного кода.
Использование открытого кода означает также, что исходный код AspectJ был предметом серьезного общественного обсуждения, прежде чем появиться на рынке.
В AspectJ релиз включены несколько инструментальных средств. Это свидетельствует о твердых обязательствах авторов AspectJ в части создания дружественного по отношению к разработчикам средства. Инструментальная поддержка чрезвычайно важна для аспектно-ориентированных систем, поскольку программные модули могут зависеть от других модулей, о наличии которых они не знают.
Строка 259 ⟶ 261 :
 
=== Заключение ===
Стоит ли использовать AspectJ? Гради Буч описывает аспектно-ориентированное программированиеАОП как одно из трех направлений, которые в совокупности знаменуют начало фундаментальных изменений в способах проектирования и написания программного обеспечения (см. статью <s>[http://www.sdmagazine.com/documents/s=843/sdm0107i/0107i.htm Through the Looking Glass]</s>). С ним вполне можно согласиться. Сфера действия AOPАОП охватывает пространство проблем, непосильных для объектно-ориентированных и процедурных языков. Оно предлагает элегантные пути для реализации задач, решение которых сдерживалось из-за фундаментальных ограничений программирования. Было бы справедливо сказать, что AOPАОП представляет собой одну из самых мощных абстракций в программировании с момента появления объектов.
 
Разумеется, для AspectJ есть некоторая «кривая обучения». Как в любом языке или расширении языка программирования, в нем есть свои тонкости, которые необходимо освоить, прежде чем задействовать всю мощь этого средства. Однако, «кривая обучения» не слишком крутая — по прочтении руководства пользователя и после проработки нескольких примеров можно составлять полезные аспекты. AspectJ воспринимается естественно, поскольку скорее заполняет пробел в знаниях по программированию, чем придает им новое направление.
прежде чем задействовать всю мощь этого средства. Однако, «кривая обучения» не слишком крутая — по прочтении руководства пользователя и после проработки нескольких примеров можно составлять полезные аспекты. AspectJ воспринимается естественно, поскольку скорее заполняет пробел в знаниях по программированию, чем придает им новое направление.
Способность AspectJ к «модулированию немодулируемого» должна найти достойное применение. Если вы пока не готовы использовать AspectJ в полном объеме для разработки, его на первых порах можно легко применить в отладке, не упуская благоприятных возможностей, предоставляемых этим расширением.
 
=== Ссылки ===
* {{cite web
* [http://www.aspectj.org AspectJ.org] — официальный ресурс AspectJ
| url = http://www.aspectj.org
* [http://www.aosd.net aosd.net] — портал поклонников аспектно-ориентированного программирования
| title = <s>AspectJ.org</s>
| lang = en
| accessdate = 27.10.2010
* | [http://www.aspectj.orgdescription AspectJ.org] —= официальный ресурс AspectJ
}}
* {{cite web
| url = http://www.aosd.net
| title = aosd.net
| lang = en
| accessdate = 27.10.2010
* | [http://www.aosd.netdescription aosd.net] —= портал поклонников аспектно-ориентированного программирования
}}
 
== [[Лисп]] ==
{{Эпиграф|В Лиспе, если охота аспектно-ориентированного программирования, нужно лишь настругать немного макросов, и готово. В Java, нужен Грегор Кичалес, создающий новую фирму, и месяцы и годы попыток заставить всё работать.}}
{{Подпись|— [http://www.norvig.com/ Петер Норвиг]}}
Строка 275 ⟶ 288 :
[…]
 
[[Категория:ПрограммированиеОбъектно-ориентированное программирование]]
[[Категория:Java]]