- Aspektorientierung
-
Aspektorientierte Programmierung (AOP) ist ein Programmierparadigma, das anstrebt, verschiedene logische Aspekte eines Anwendungsprogramms (kurz Anwendung) getrennt voneinander zu entwerfen, zu entwickeln und zu testen. Die getrennt entwickelten Aspekte werden dann zur endgültigen Anwendung zusammengefügt.
Aspekte beziehungsweise Concerns in diesem Sinne sind alle eigenständigen Anforderungen der Anwendung, die nicht einem einzigen (Klassen-)Modul zugeordnet werden können sondern vielmehr von mehreren Modulen berücksichtigt werden müssen. Bei einer Lagerverwaltung zum Beispiel sind Bestandsverwaltung, Disposition und Nachschub mögliche Module. Aspekte sind z. B. Anforderungen wie Transaktionsverwaltung, Auditfähigkeit und Loggingverhalten, die für alle Module in der Lagerverwaltung gelten. Also behandelt ein Aspekt einen querschnittlichen Belang von mehreren Softwaremodulen.
Die AOP erweitert klassisch objektorientierte Sprachen um syntaktische Elemente, die es ermöglichen, diese querschnittlichen Belange gekapselt und modulübergreifend zu definieren und diese den betroffenen, in mehreren Modulen verstreuten Codefragmenten zuzuordnen.
Das Konzept von AOP wurde von Gregor Kiczales und seinem Team bei der Firma Xerox PARC entwickelt. Dort entstand auch die erste AOP-Sprache AspectJ.
Motivation
Software hat grundsätzlich bestimmte Aufgaben/Anforderungen zu erfüllen. Diese Anforderungen kann man grob in zwei Bereiche gliedern:
- Die sogenannten Core-Level-Concerns (betreffen den logischen „Kern“ der Anwendung) oder funktionale Anforderungen. Dies sind Anforderungen an die Software, die man meist gut in einzelnen Funktionen kapseln kann. Ein Beispiel wäre die Berechnung eines Wertes.
- Die System-Level-Concerns (betreffen das gesamte System) oder technische Randbedingungen. Diese Anforderungen können nicht einfach gekapselt werden, da sie an vielen Stellen implementiert werden müssen. Ein Paradebeispiel dafür ist das Logging, die Protokollierung des Programmablaufs in sogenannten Logdateien. Der Aufruf des Loggers ist für die eigentliche Funktionalität nicht notwendig, muss aber trotzdem in den Quelltext integriert werden. Ein weiteres Beispiel wäre die Transaktionierung von Zugriffen auf eine Ressource wie z. B. eine Datenbank.
Diese beiden Teile sind miteinander „verwoben“. Die Core-Level-Concerns kann man als Komponenten bezeichnen und die System-Level-Concerns sind die Aspekte. Core-Level-Concerns werden üblicherweise als Module oder Objekte implementiert. Für die Aspekte gab es vor der Aspektorientierten Programmierung keine elegante Lösung.
Das Problem der miteinander verwobenen Anforderungen wird auch als Cross-Cutting Concerns bezeichnet, denn sie „schneiden“ quer durch alle logischen Schichten des Systems. AOP ist das Werkzeug, um die logisch unabhängigen Belange auch physisch voneinander zu trennen. Dabei wird angestrebt, Code zu erzeugen, der besser wartbar und wiederverwendbar ist.
In diesem Zusammenhang sind System-Level-Concerns aber nicht gleichzusetzen mit rein technischen Belangen. Auch fachliche Belange wie z. B. die Umsetzung eines eigenen, fachlichen Berechtigungssystems für Benutzer können durchaus Aspektcharakter haben.
Hintergrund
In der Geschichte der Entwicklung der Programmiersprachen wurden immer wieder neue Konzepte der Programmierung und diese implementierende Hochsprachen entwickelt, angefangen bei der Programmierung in Assembler, welche das direkte Programmieren in Binärcode ablöste, über prozedurales und funktionales Programmieren, bis hin zu den heute aktuellen objektorientierten Sprachen. Der Zweck dieser Entwicklung war es nicht, den Rechnern eine erweiterte Funktionalität zu ermöglichen, da im Endeffekt jede Hochsprache wieder auf den durch die Hardware vorgegebenen Maschinencode abgebildet wird, sondern den Entwicklern die Arbeit zu erleichtern und somit eine bessere Effizienz in der Entwicklung der Software zu erzielen. Eines der zugrundeliegenden Prinzipien, das bei allen neuen Programmierkonzepten angewendet wurde, war das der Kapselung von Funktionalität.
- Assemblersprachen kapseln hardwareabhängige Binärbefehle für Arbeitsspeicher und Registerzugriffe in kurzen, generalisierten Zeichenketten, und befreien den Softwareentwickler damit von der Notwendigkeit, sich mit dem detaillierten Aufbau der gesamten Rechnerhardware zu beschäftigen.
- Prozedurale Sprachen erlauben die Kapselung von einfachen Funktionen, wie das Sortieren einer Namensliste, innerhalb einer Prozedur. Damit entfallen die Notwendigkeit von Zeilennummern und daran gebundenen Sprungbefehlen sowie das mehrfache Entwickeln derselben Funktion an verschiedenen Stellen des Programmcodes.
- Objektorientierte Programmiersprachen erlauben die Kapselung konzeptionell zusammengehöriger Funktionen und Variablen in unabhängigen Modulen (Klassen) mit klar definierten Schnittstellen, wodurch die Wiederverwendbarkeit der einzelnen Module erhöht wird und der Softwareentwickler davon befreit ist, sich mit der internen Implementierung der von ihm verwendeten Klassen auseinanderzusetzen.
Insbesondere erleichtert die Kapselung von Funktionalität dem Softwareentwickler die Entwicklung durch Erhöhung der Wartbarkeit und Wiederverwendbarkeit von existierendem Programmcode. Da Software im Laufe der Zeit immer komplexer und umfangreicher wird und damit die Entwicklung zeitaufwendiger und teurer, gewannen diese beiden Ziele immer mehr an Bedeutung und sind heute zentrale Elemente bei der Entwicklung neuer Programmierkonzepte und -sprachen.
Bei AOP (Aspect-Oriented Programming bzw. Aspektorientierte Programmierung) handelt es sich um ein Programmierkonzept, welches das Problem der sogenannten Cross-Cutting Concern behandelt.
Die kostengünstige und termingerechte Entwicklung und Wartung qualitativ hochwertiger Software ist das Primärziel des Software Engineering. Um dieses Ziel zu erreichen, ist eine möglichst modularisierte Software mit einer möglichst geringen Komplexität der Module notwendig.
In einem konventionellen System, wobei hier auch die objektorientierten Ansätze hinzugehören, können Kernfunktionalitäten, englisch core concerns, für sich allein betrachtet nach den Regeln der Kunst sauber in Module getrennt werden. Es gibt jedoch concerns (Anliegen, Belange, Anforderungen) wie Fehlerbehandlung, Performance und Sicherheit in jedem System, die die Kernfunktionalitäten quer schneiden (eng. cross cut) und sich deshalb nicht eindeutig einem Software-Modul zuordnen lassen. Dies führt dazu, dass Fragmente solcher cross cutting concerns (quer schneidende Kernfunktionalitäten (übergreifende Anforderungen) – fehlende Kohäsion) nicht zugeordnet und ungekapselt im ganzen Code verstreut sind. Diese quer schneidenden Kernfunktionalitäten verhindern in konventionellen Softwaresystemen eine saubere Modularisierung und beeinträchtigen Pflege, Verständlichkeit, Wiederverwendbarkeit und (Rück-)Verfolgbarkeit. Verantwortlich hierfür ist bei konventionellen Programmiersprachen die Systemdekomposition, die nur eine Dimension zulässt – die Liste von Funktionen. Dieses Phänomen nennt man auch dominante Dekomposition. Mit anderen Worten: ein natürlicherweise mehrdimensionales Problem muss eindimensional gelöst werden.
Erklärung als Ableitung von prozeduraler und objektorientierter Programmierung
In der prozeduralen Programmierung ist die Ausführung von Code vergleichsweise linear. Durch Verfolgung der Symbole ist jeder einzelne Programmschritt auch bei der Betrachtung eines Teilsystems direkt nachvollziehbar. Beispiel in C:
void function (void * c) { Component_repaint(c); }
Die Funktion
Component_repaint()
ist eindeutig. Unabhängig davon, ob der Zeigerc
den dynamischen TypComponent
oder einen abgeleiteten Typ hat, wird immer dieselbe FunktionComponent_repaint(Component*)
aufgerufen (statische Typisierung).In der objektorientierten Programmierung wird die Nachvollziehbarkeit durch die Polymorphie reduziert. Beispiel in Java:
void function (Component c) { c.repaint(); }
Es ist nicht eindeutig nachvollziehbar, welche
repaint()
-Methode ausgeführt wird, das hängt vom tatsächlichen Typ des Objekts ab, das vonc
referenziert wird. Ein vonComponent
abgeleiteter Typ könnte seine eigenerepaint()
-Methode definieren, indem er die vonComponent
geerbte Methoderepaint()
überschreibt.In der aspektorientierten Programmierung wird die Nachvollziehbarkeit durch die Verwendung von Pointcuts weiter reduziert. Ein Pointcut enthält für einen Join-Point auszuführenden Code, ein Join-Point ist dabei ein genau definiertes Aufrufereignis. Beispiel in AspectJ:
void function (Component c) { c.repaint(); }
Hier können zu nahezu beliebigen Punkten in der Aufrufkette Advices aktiviert werden. Damit ist es im Extremfall sogar möglich, den Aufruf der Methoden
function()
oderrepaint()
an sich zu verhindern. So könnte man sich einen Aspekt vorstellen, der für den Join-Point „Aufruf der Methodefunction()
“ einen Advice definiert, der explizit die weitere Abarbeitung dieses Funktionsaufrufs untersagt. Ebenso könnte man in einem Advice festlegen, dass anstatt der Methoderepaint()
eine andere Methode auf das Objekt angewandt werden soll. Die Information darüber, was als nächstes geschehen soll, ist dabei am Ort des Geschehens selbst zunächst nicht abzulesen.Zum besseren Verständnis der Konzepte von Pointcuts, Join-Points und Advices sei der folgende Vergleich mit der Structured Query Language (SQL) erlaubt: Man stelle sich ein SELECT-Statement vor, das alle Methoden in allen Klassen eines Systems selektieren kann. In diesem Zusammenhang entspricht dann
- ein Pointcut der WHERE-Klausel, welche die Menge der selektierten Methoden einschränkt
- ein Join-Point einem konkreten Suchergebnis im Sinne eines Satzes aus einer Datenbank – nur, dass hier keine Sätze aus einer Datenbank selektiert werden, sondern Methoden in einem System
- ein Advice ist dann die Methode in einem Aspekt, die vor, nach oder anstatt der ausgewählten Methode ausgeführt werden soll.
Während in der prozeduralen Programmierung die Nachvollziehbarkeit durch ein Quelltextfragment und in der objektorientierten Programmierung unter zusätzlicher Kenntnis über die Laufzeittypen vergleichsweise direkt gegeben ist, erfordert die Nachvollziehbarkeit in der aspektorientierten Programmierung die Kenntnis sämtlicher Aspekte, die Point-Cuts für die Join-Points des Code-Fragment definieren.
Orthogonal bedeutet hier, dass Eigenschaften von Methoden „senkrecht“ zur normalen Programmierrichtung definiert werden. Die tatsächliche Code-Ausführung wird nicht nur durch die Aufruf- und Typenhierarchie, sondern zusätzlich „senkrecht“ (orthogonal) dazu von den Aspekten definiert.
Analogie
Anschaulich kann man sich das Prinzip wie folgt vorstellen: ein Programm, gleichgültig ob prozedural oder objektorientiert, folgt einem Programmablaufplan, d. h. der Programmfluss ist an jeder Stelle durch lineare Folgen von Anweisungen (Codeblöcke) und Sprünge zwischen diesen (z. B. Methodenaufrufe) festgelegt. Ein Aspekt wäre hier soviel wie eine Schablone, die über diesen Originalplan gelegt wird und verschiedene Änderungen oder Ergänzungen am Ablaufschema vornimmt. Änderungen an der Schablone lassen den Originalplan unangetastet, die Schablone lässt sich jederzeit austauschen, mit anderen kombinieren oder wieder entfernen.
Technische Betrachtung
In einer objektorientierten Laufzeitumgebung könnte aspektorientierte Programmierung durch veränderbare Sprungvektoren ermöglicht werden. Man kann sie als eine Art im Programmierparadigma vorgesehenes „Patchen“ von Funktionen ansehen.
Ein Objekt C wird in die Lage versetzt, Interaktionen zwischen zwei Objekten A und B zu überwachen, ohne dass dafür Veränderungen oder Erweiterungen an A und B notwendig sind. Natürlich ist tatsächlich doch eine Veränderung von A oder B oder beiden notwendig. AspectJ erzeugt diese Änderungen automatisch, der Vorgang dafür heißt Weaving, da besagte Änderungen vor dem Kompilieren in den Originalcode „eingewebt“ werden.
Einsatzgebiete
Die aspektorientierte Programmierung ist in der Lage, die bisher in der objektorientierten Programmierung eingesetzte ereignisgesteuerte Programmierung (Event-Handling) ganz zu ersetzen. Die ereignisgesteuerte Programmierung dient dazu, ein Objekt X über Veränderungen an einem Objekt Y zu benachrichtigen. Das Objekt Y braucht das Objekt X dabei aber nicht zu kennen. Die bisherige Lösung wird hier am Beispiel eines Fensters in Java (java.awt.Frame) erklärt. Zu Ereignissen, die speziell für Fenster eintreten und über die ein anderer Programmteil benachrichtigt werden soll, zählt unter anderem das Schließen, das Aktivieren und das Deaktivieren. Eine Schnittstelle java.awt.event.WindowListener definiert dafür unterschiedliche Methoden und muss von den Objekten, die über Veränderungen am Fenster benachrichtigt werden möchten, implementiert werden. Objekte, die benachrichtigt werden möchten, müssen sich bei dem jeweiligen anderen Objekt registrieren. Die aspektorientierte Programmierung kann die Definition solcher Schnittstellen überflüssig machen. Ein Aspekt X definiert für das zu überwachende Objekt Y die genau zu überwachenden Code-Ereignisse, genannt Point-Cut, zusammengesetzt aus Join-Points (Gesamte Methode, Methoden-Aufruf, Methoden-Rückkehr unterscheidbar in Methoden-Rückkehr mit Rückgabewert und Methoden-Rückkehr mit Exception), und definiert für die verschiedenen Point-Cuts den Advice, das ist der auszuführende Code. Die Ausführung von Code in X durch Veränderungen an einem Objekt Y kann also ohne zusätzliches Interface, Methoden und Registrierungsmechanismus erfolgen.
Aspektorientierte Programmierung kann bei der Entwicklung von Frameworks (Libraries) eingesetzt werden um z. B. Eigenschaften wie Persistenz oder Synchronisierbarkeit zu implementieren. Der Transfermechanismus bleibt dann vor dem Benutzer der Bibliothek verborgen. Das Verbergen des Transfermechanismus macht den Code in diesem Fall übersichtlicher, da die Methoden nicht mit Framework-Code überfrachtet werden.
Ein weiteres Einsatzgebiet ist das Software-Testen, wo insbesondere das Einführen neuer Attribute in Klassen ohne die Veränderung ihrer Quelltexte (Inter-type Declarations) neue interessante Möglichkeiten für die Entwicklung von White-Box-Tests darstellt, z. B. um ein Tracing privater Attribute durchzuführen.
Joinpoint vs. Joinpoint shadow
Es muss zwischen Joinpoints und den sogenannten Joinpoint shadows unterschieden werden. Ein Joinpoint shadow ist das statische Vorkommen eines potentiellen Joinpoints. Ob dieser shadow (etwa ein im Quellcode stehender Methodenaufruf) tatsächlich zu einem Joinpoint wird, entscheidet sich erst zur Laufzeit in Abhängigkeit vom korrespondierenden Pointcut (resp. Pointcut-Designator).
Ein Pointcut definiert eine Menge von Joinpoint shadows, die er aus dem zugrunde liegenden Programm herausschneidet (cut). Wird während des Programmablauf ein Joinpoint shadow betreten und ist sein definierender Pointcut erfüllbar, wird der "Joinpoint shadow" zum "Joinpoint".
Beispiel
Folgendes Beispiel erläutert den Grundgedanken der aspektorientierten Programmierung. Die verwendete Programmiersprache ist AspectJ, die Java um die Aspektorientierung erweitert.
Einführendes Beispiel
Als einführendes Beispiel soll eine Standardaufgabe bei der Softwareentwicklung dienen: Tracing von Informationen in eine Datei. Das Vorgehen ohne aspektorientierte Programmierung besteht darin, einen Logger zu erzeugen und dort eine entsprechende Methode aufzurufen, die die eigentliche Information in die Logdatei speichert:
public void eineMethode() { logger.trace("Betrete "eineMethode""); // Abarbeitung der Methode m = a + 2; logger.trace("Verlasse "eineMethode""); }
Zu Beginn der Methode wird an den Logger gemeldet, dass die Methode betreten wird. Danach folgt die eigentliche Logik der Methode. Zum Schluss wird das Verlassen der Methode protokolliert.
In einer typischen Anwendung sind derartige Methodenaufrufe an den Logger in vielen Methoden und Klassen vorhanden – sie sind über die gesamte Anwendung verstreut und keinesfalls modular. Der Logger muss
- jedem Objekt bekannt gemacht werden, und
- kann nicht ohne weiteres an einer zentralen Stelle ausgetauscht werden – jedenfalls nicht, ohne diesen im System public static zu deklarieren, was einer globalen Variablen und somit zweifelhaftem Design gleichkommt.
Somit wird auch klar was mit Semantisch und physisch unabhängige Programmstrecken gemeint ist. In obiger Methode sind zwei eigentlich unabhängige Aufgaben miteinander vermengt. Dies ist zum einen das Protokollieren und zum anderen die eigentliche Logik der Methode, die darin besteht, das Ergebnis einer Addition in der Membervariablen m zu speichern.
Die aspektorientierte Programmierung erlaubt es nun, auch Aufgaben wie das Tracing zu modularisieren. Angenommen, das Betreten und Verlassen einer jeden Methode der Klasse soll auf die oben gezeigte Weise protokolliert werden. Gegenüber der konventionellen Programmierung lässt sich eine solche Anweisung in der AOP direkt als Aspekt formulieren:
public aspect Tracing { pointcut traceCall(): call(* AOPDemo.*(..)); before(): traceCall() { System.out.println("Betrete "" + thisJoinPoint + """); } after(): traceCall() { System.out.println("Verlasse "" + thisJoinPoint + """); } }
Im Aspekt wird bestimmt, dass alle Methoden der Klasse AOPDemo unabhängig von ihrer Signatur einbezogen werden sollen. Die Aufgaben werden auf diese Weise separiert und die ursprüngliche Methode kann verkürzt geschrieben werden:
public void eineMethode() { // Abarbeitung der Methode m = a + 2; }
Weiterführendes Beispiel
Außerdem ermöglicht die Aspektorierte Programmierung eine Umleitung des ursprünglichen Programmablaufs. Sicherheitsaspekte können zum Beispiel den ursprünglichen Programmablauf austauschen, um unberechtigte Zugriffe auf geschützte Programmteile zu verhindern. Caching-Aspekte erhöhen die Ausführungsgeschwindigkeit von Programmen und werden eingesetzt, um den Aufruf aufwendiger Programmteile wie Datenbank- oder Dateisystemzugriffe zu reduzieren. Das folgende Beispiel demonstriert die Umleitung von Methodenaufrufen bzw. den Austausch von Programmteilen als Interception Around Advice:
public aspect Caching { pointcut cacheCall(): call(* AOPDemo.*(..)); private Map cache = new Map(); around(): cacheCall(Joinpoint joinPointContext) { // Prüfen, ob Rückgabewert für aktuelle Aufruf-Argumente schon im Cache abgelegt wurde Object args = joinPointContext.getArguments(); boolean isCallCached = cache.containsKey(args); if (isCallCached) { // Umleitung und Austausch des ursprünglichen Methodenaufrufs, gesicherten Rückgabewert aus Cache verwenden Object cachedReturnValue = cache.get(args); return cachedReturnValue; } else { // Weiterleitung an ursprüngliche Methode und neuen Rückgabewert im Cache sichern Object newReturnValue = joinPointContext.proceed(); cache.put(args, newReturnValue); return newReturnValue; } } }
Begrifflichkeit
Das Beispiel beinhaltet bereits die wichtigsten Konzepte, wenn auch nicht alle. In diesem Abschnitt werden die fehlenden hinzugefügt und den in der AOP verwendeten Begriffen zugeordnet.
Dazu wird das Beispiel um folgende Codesequenz erweitert und der bisherige Ablauf grafisch dargestellt:
public void quellMethode() { eineMethode(); }
Der Aspekt kommt zum Tragen, noch bevor
eineMethode()
betreten wird. Der Grund dafür ist der Join Point direkt davor. Diese Join Points sind implizit gegeben. Das heißt sie sind vor jeder Methode vorhanden. Das Muster, das aus allen vorhandenen Join Points diejenigen aussucht, die für einen Aspekt interessant sind, nennt sich Pointcut. Tatsächlich handelt es sich bei den Pointcuts um Muster, die auch Wildcards erlauben. Um festzulegen, wann welcher Code innerhalb des Aspekts auszuführen ist, kommen Advices zum Tragen. Im Einführenden Beispiel sind dies before und after, im weiterführenden Beispiel around. Diese Advices sind, neben weiteren, implizit gegeben.Die Programmierung mit Aspekten erlaubt es zudem, in und mit Aspekten das Verhalten von Klassen zu verändern. Es können durch Aspekte Felder und Methoden zu Klassen hinzugefügt werden. Auch hier ist es durch die Angabe von Wildcards gleichzeitig bei mehreren Klassen möglich. In einer Sprache wie Java verletzen diese Inter-Type Declarations die Regel, dass sämtliche Felder und Methoden einer Klasse in einer Datei, bzw. der Vererbungshierarchie der Klasse zu finden sind, da Aspekte dieser nicht angehören.
Typische Aufgaben
AOP ist besonders zur Programmierung von sogenannten Cross-Cutting Concerns geeignet. Beispiele dafür sind Protokollierung, Fehlerbehandlung, Persistenz, Validierung und Security.
Profiling APIs, wie bspw. in Java enthalten, arbeiten auf ähnliche Weise wie AOP. Sie dienen dazu, unperformante Codestellen zu ermitteln. Dazu werden durch einen sog. Profiler Zeitmessungen für die Abarbeitung sämtlicher Methoden angestellt. Der eigentliche Profiler kann sich von der Virtual Machine mitteilen lassen, wann eine Methode betreten und verlassen wird. Mit aspektorientierter Programmierung lässt sich daher auch ein Profiler realisieren.
Ähnliche Lösungsansätze
Aspekte haben ihren Ursprung in der objektorientierten Programmierung und sind zumindest in ihrer Intention vergleichbar mit Metaobjektprotokollen, wie man sie beispielsweise im Common Lisp Object System vorfindet. Ferner sind Aspekte mit Konzepten wie der subjektorientierten Programmierung, den Mix-Ins, den Classboxes oder dem Konzept der Delegierung verwandt, wie es in der Programmiersprache Self vorzufinden ist. Einen ähnlich gelagerten oder gar gleichwertigen Lösungsansatz stellen die sogenannten Traits dar.
Entwicklungsstand der aspektorientierten Programmierung
Die aspektorientierte Programmierung steckt heute noch in den Kinderschuhen. AspectJ z. B. stellt keine vollständig aspektorientierte Lösung dar, weil die Aspektorientierung sich nur auf Klassen beschränkt, die von AspectJ compiliert werden, nicht jedoch für Klassen gilt, die lediglich verwendet werden. Das besonders interessante Einsatzgebiet der Überwachung von Collections ist damit nur sehr eingeschränkt möglich.
Außerdem ist strittig, ob und wie aspektorientierte Programmierung auf Objekt-Ebene zu realisieren ist. Schnell, aber enorm speicherintensiv sind Patchlisten für jedes einzelne Objekt. Eine Lösung könnte die Einführung einer Methodeneigenschaft „controllable“ oder „aspect“ sein, welche als Join-Point verwendbare Methoden kennzeichnet, vergleichbar mit „virtual“ in C++, das polymorphe Methoden kennzeichnet. Jedoch zeigen einerseits moderne OO-Sprachen wie Java auf Objektebene ausschließlich virtuelle Methoden, was ein Indikator dafür ist, eine solche Einschränkung nicht einzuführen, andererseits ist eine derartige Einschränkung wider die Natur der aspektorientierten Programmierung. Andere Ansätze, wie AspectJ, beschränken sich auf die Aspektorientierung auf Klassenebene, die gezielte Überwachung bestimmter einzelner Objekte ist nicht deklarativ möglich.
Zahlreiche bestimmte Erfahrungen müssen auch erst noch gemacht werden. Klassische Entwurfsmuster, Refaktorisierungen und Fallstricke der Objektorientierung waren schließlich auch nicht von Anfang an bekannt. Auch heute noch kranken zahlreiche OO-Programme an Fehlentwürfen bezüglich der Mutability (Zugriffsart) von Attributen und damit unnötigen defensiven Objektkopien.
Bis sich die aspektorientierte Programmierung zu einem dominierenden Programmierparadigma wie heute die objektorientierte Programmierung entwickelt hat, dürften noch einige Jahre und Programmiersprachen ins Land gehen. AspectJ ist dabei mit den ersten OO-Schritten in C vergleichbar, aus denen später Objective C und C++ hervorgegangen sind. Man kann davon ausgehen, dass sich auf der Basis der objektorientierten Programmiersprachen Java und C# aspektorientierte Programmiersprachen entwickeln werden, wie einst Oberon und C++ aus Pascal und C entstanden sind. Diese werden den Programmierern ermöglichen, die Aspektorientierung zu erkunden, aspektorientierte Programmiermuster zu entwerfen und schließlich zur Entwicklung ausgereifter aspektorientierter Sprachen und Laufzeitumgebungen führen, wie heute Java oder C# für die Objektorientierung.
Ebenso kann es zu einem Versiegen von Neuentwicklungen im AOP Bereich kommen, wenn die höhere Abstraktion in der Praxis nicht von einem ausreichenden Anteil von Entwicklern verstanden und eingesetzt wird. Aktuell werden bereits OO-Techniken häufig nicht im Sinne der ursprünglichen Konzeption, sondern ausschließlich zur Erfüllung von Vorgaben eingesetzt. Vor diesem Hintergrund ist das Potential für noch weiter abstrahierende Techniken ungewiss.
Zukünftige Entwicklung
Die weitere Entwicklung des aspektorientierten Ansatzes ist aktuell nicht abzusehen. In Deutschland forschen u. a. die TU Darmstadt, die TU Berlin, das Hasso-Plattner-Institut und die Universität Bonn auf diesem Gebiet (siehe Weblinks).
Anmerkungen
Vorteil der Aspektorientierung ist die logische und physische Trennung der Semantik (der Komponente) von dem technischen Detail (Aspekt). Als Nachteil der aspektorientierten Programmierung sei hier insbesondere der Overhead erwähnt, der nach dem Weaving im generierten Programm entsteht. Dies führt im Allgemeinen zu Performance-Einbußen. Des Weiteren reduziert aspektorientierte Programmierung die Nachvollziehbarkeit von Programmverhalten, da die Stellen, an denen ein Aspekt zuständig ist, im betroffenen Code nicht direkt erkennbar sind. Debugging wird so stark erschwert, allerdings kann dieser Nachteil durch Unterstützung einer IDE neutralisiert oder zumindest reduziert werden, indem das Debugging ebenso mehrdimensional vor sich geht wie das Entwickeln des Codes.
Ein weiterer Nachteil ist, dass beim Einsatz dieser Technik unerwünschte und schwer nachvollziehbare Wechselwirkungen zwischen einzelnen Aspekten auftreten können.
Aspekte und Komponenten können in verschiedenen Programmiersprachen definiert sein.
Implementierungen in Programmiersprachen
- Für C#/VB.NET:
- LOOM.NET
- Puzzle.NAspect
- AspectDNG
- Aspect#
- Encase
- Compose*
- PostSharp
- Seasar.NET
- DotSpect (.SPECT)
- The Spring Framework als Teil ihrer Funktionalität
- Eine ausführliche Analyse in Englisch zu AOSD Lösungen für .NET an der Twente University
- Für Java:
- AspectJ
- Spring – AOP
- AspectWerkz (Now merged with AspectJ)
- CaesarJ
- Dynaop
- Guice – lightweight Method AoP
- JAC
- Jakarta Hivemind
- Javassist Home Page
- JAsCo (and AWED)
- JAML
- JBoss AOP
- LogicAJ
- Objectteams
- PROSE
- The AspectBench Compiler for AspectJ (abc)
- The Spring Framework as part of its functionality
- en:Seasar
- The JMangler Project
- InjectJ
- Für C/C++:
- en:AspectC++ ([1])
- XWeaver project
- FeatureC++
- AspectC
- Für Hardwarebeschreibungssprachen:
- 'e' (IEEE 1647)
- Für Python:
- Aspyct
- Lightweight Python AOP
- Logilab’s aspect module
- Python/Transwarp AOP Tutorial Übergegangen in PEAK
- PEAK
- Pythius
- Für PHP:
- Für Perl:
- Für Common Lisp:
- Für Cocoa:
- Für Squeak Smalltalk
- Für ColdFusion:
- Für Actionscript 3.0
- Für Cobol:
Noch nicht entwickelt
Siehe auch
Literatur
- Lars Wunderlich: AOP: Aspektorientierte Programmierung in der Praxis. Entwickler.press, Frankfurt am Main 2005, ISBN 3-935042-74-4
- Oliver Böhm: Aspektorientierte Programmierung mit AspectJ 5: Einsteigen in AspectJ und AOP. Dpunkt Verlag, Heidelberg 2006, ISBN 3-89864-330-1
- Renaud Pawlak, Lionel Seinturier, Jean-Philippe Retaille: Foundations of AOP for J2EE Development (Foundation). Apress, Berkeley, Kalifornien, USA 2005, ISBN 1-59059-507-6
- Ralf Westphal: Aspektorientierte Programmierung mit .NET dotnetpro 10/2007
Weblinks
- AspectL Website. Aspektorientierte Programmierung für Lisp
- AspectJ Website. Aspektorientierte Programmierung für Java
- Aspektorientierte Programmierung an der TU Darmstadt
- Aspektorientierte Programmierung an der Uni Bonn
- TOPPrax Forschungsprojekt der TU-Berlin. Aspektorientierte Programmierung für die Praxis.
- Aspect# – Aspektorientierte Programmierung für C#
- Aspektorientierte Programmierung für C++
- FeatureC++ Website. Kombination von Merkmalsorientierte Programmierung und Aspektorientierte Programmierung für C++
- Fehlersuche mit aspektorientierter Programmierung in Java (deutsch)
- phpaspect – Aspektorientierte Programmierung für PHP
- AOSD – Aspect-Oriented Software Development conference
- AspectIX – Aspekt-orientierte Middleware, basierend auf CORBA, Forschungsprojekt von Uni Ulm und Uni Erlangen-Nürnberg
- aoPHP – Aspect Oriented PHP
Wikimedia Foundation.