Aspektorientierte Programmierung vs. objektorientierte Programmierung


199

Wie die meisten Entwickler hier und auf der ganzen Welt entwickle ich seit vielen Jahren Softwaresysteme mit objektorientierten Programmiertechniken (OOP). Wenn ich also lese, dass die aspektorientierte Programmierung (AOP) viele der Probleme angeht, die mit herkömmlicher OOP nicht vollständig oder direkt gelöst werden, halte ich inne und denke, ist sie real?

Ich habe viele Informationen gelesen, um die Schlüssel dieses AOP-Paradigmas zu lernen, und ich bin am selben Ort. Deshalb wollte ich seine Vorteile bei der Entwicklung von Anwendungen in der Praxis besser verstehen.

Hat jemand die Antwort?


7
Alle Antworten waren sehr gut, dies ist ein perfekter Fall für eine einzelne von der Community bearbeitete Antwort, die sie alle kombinieren würde. Alle sagen dasselbe, aber auf unterschiedliche Weise und verwenden unterschiedliche Beispiele, die zum Gesamtwert
beitragen

Antworten:


322

Warum "vs"? Es ist nicht "vs". Sie können die aspektorientierte Programmierung in Kombination mit der funktionalen Programmierung, aber auch in Kombination mit der objektorientierten Programmierung verwenden. Es ist nicht "vs", sondern "aspektorientierte Programmierung mit objektorientierter Programmierung".

Für mich ist AOP eine Art "Meta-Programmierung". Alles, was AOP tut, könnte auch ohne es getan werden, indem einfach mehr Code hinzugefügt wird. AOP erspart Ihnen nur das Schreiben dieses Codes.

Wikipedia hat eines der besten Beispiele für diese Metaprogrammierung. Angenommen, Sie haben eine grafische Klasse mit vielen "set ... ()" - Methoden. Nach jeder eingestellten Methode haben sich die Daten der Grafiken geändert, daher haben sich die Grafiken geändert und daher müssen die Grafiken auf dem Bildschirm aktualisiert werden. Angenommen, um die Grafiken neu zu zeichnen, müssen Sie "Display.update ()" aufrufen. Der klassische Ansatz besteht darin, dies durch Hinzufügen von mehr Code zu lösen . Am Ende jeder festgelegten Methode schreiben Sie

void set...(...) {
    :
    :
    Display.update();
}

Wenn Sie 3 Set-Methoden haben, ist das kein Problem. Wenn Sie 200 haben (hypothetisch), wird es sehr schmerzhaft, dies überall hinzuzufügen. Auch wenn Sie eine neue Set-Methode hinzufügen, müssen Sie nicht vergessen, diese am Ende hinzuzufügen, da Sie sonst gerade einen Fehler erstellt haben.

AOP löst dieses Problem, ohne Tonnen von Code hinzuzufügen. Stattdessen fügen Sie einen Aspekt hinzu:

after() : set() {
   Display.update();
}

Und das ist es! Anstatt den Update-Code selbst zu schreiben, teilen Sie dem System einfach mit, dass es nach Erreichen eines set () -Punktschnitts diesen Code ausführen muss und diesen Code ausführen wird. Keine Notwendigkeit, 200 Methoden zu aktualisieren, keine Notwendigkeit sicherzustellen, dass Sie nicht vergessen, diesen Code einer neuen Set-Methode hinzuzufügen. Zusätzlich benötigen Sie nur einen Pointcut:

pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);

Was bedeutet das? Das heißt , wenn eine Methode den Namen „Set *“ (* bedeutet einen beliebigen Namen nach Satz folgen könnte), und zwar unabhängig davon , was die Methode zurückgibt (erste Sternchen) oder welche Parameter es (dritte Stern) nimmt und es ist eine Methode der MyGraphicsClass und diese Klasse ist Teil des Pakets "com.company. *", dann ist dies ein set () pointcut. Und unser erster Code lautet " Führen Sie nach dem Ausführen einer Methode, die ein Sollwert ist, den folgenden Code aus".

Sehen Sie hier, wie AOP das Problem elegant löst? Eigentlich kann alles, was hier beschrieben wird, zur Kompilierungszeit gemacht werden. Ein AOP-Präprozessor kann einfach Ihre Quelle ändern (z. B. Display.update () am Ende jeder Sollwertmethode hinzufügen), bevor er die Klasse selbst kompiliert.

Dieses Beispiel zeigt jedoch auch einen der großen Nachteile von AOP. AOP macht tatsächlich etwas, das viele Programmierer als " Anti-Pattern " betrachten. Das genaue Muster heißt " Fernwirkung ".

Fernwirkung ist ein Anti-Muster (ein erkannter häufiger Fehler), bei dem das Verhalten in einem Teil eines Programms stark variiert, je nachdem, ob Operationen in einem anderen Teil des Programms schwierig oder unmöglich zu identifizieren sind.

Als Neuling in einem Projekt könnte ich einfach den Code einer Set-Methode lesen und ihn als fehlerhaft betrachten, da er die Anzeige nicht zu aktualisieren scheint. Ich nicht sehen , indem nur auf dem Code einer Set-Methode sucht, dass , nachdem er ausgeführt wird, wird ein anderer Code „magische Weise “ die Anzeige aktualisieren ausgeführt werden. Ich halte das für einen ernsthaften Nachteil! Durch Änderungen an einer Methode können seltsame Fehler auftreten. Ein besseres Verständnis des Codeflusses von Code, bei dem bestimmte Dinge korrekt zu funktionieren scheinen, aber nicht offensichtlich sind (wie gesagt, sie funktionieren einfach magisch ... irgendwie), ist wirklich schwierig.

Aktualisieren

Nur um das zu verdeutlichen: Einige Leute haben vielleicht den Eindruck, dass AOP etwas Schlechtes ist und nicht verwendet werden sollte. Das sage ich nicht! AOP ist eigentlich eine großartige Funktion. Ich sage nur "Verwenden Sie es vorsichtig". AOP verursacht nur dann Probleme, wenn Sie normalen Code und AOP für denselben Aspekt verwechseln . Im obigen Beispiel haben wir den Aspekt, die Werte eines grafischen Objekts zu aktualisieren und das aktualisierte Objekt zu malen. Das ist in der Tat ein einziger Aspekt. Das Codieren der Hälfte davon als normaler Code und der anderen Hälfte als Aspekt ist das, was das Problem hinzufügt.

Wenn Sie AOP für einen völlig anderen Aspekt verwenden, z. B. für die Protokollierung, wird das Anti-Pattern-Problem nicht auftreten. In diesem Fall könnte sich ein Neuling im Projekt fragen: "Woher kommen all diese Protokollnachrichten? Ich sehe keine Protokollausgabe im Code", aber das ist kein großes Problem. Änderungen, die er an der Programmlogik vornimmt, werden die Protokollfunktion kaum beschädigen, und Änderungen an der Protokollfunktion werden seine Programmlogik kaum beschädigen - diese Aspekte sind vollständig voneinander getrennt. Die Verwendung von AOP für die Protokollierung hat den Vorteil, dass sich Ihr Programmcode voll und ganz auf das konzentrieren kann, was er tun sollte, und dass Sie dennoch eine ausgefeilte Protokollierung durchführen können, ohne dass Ihr Code überall von Hunderten von Protokollnachrichten überladen wird. Auch wenn neuer Code eingeführt wird, werden magische Protokollnachrichten zur richtigen Zeit mit dem richtigen Inhalt angezeigt.

Eine gute Verwendung von AOP in meinem Beispiel wäre also, immer zu protokollieren, wenn ein Wert über eine festgelegte Methode aktualisiert wurde. Dies wird kein Anti-Muster erzeugen und kaum jemals die Ursache eines Problems sein.

Man könnte sagen, wenn Sie AOP leicht missbrauchen können, um so viele Probleme zu verursachen, ist es eine schlechte Idee, alles zu verwenden. Welche Technologie kann jedoch nicht missbraucht werden? Sie können die Datenkapselung missbrauchen, Sie können die Vererbung missbrauchen. So ziemlich jede nützliche Programmiertechnologie kann missbraucht werden. Stellen Sie sich eine Programmiersprache vor, die so eingeschränkt ist, dass sie nur Funktionen enthält, die nicht missbraucht werden können. Eine Sprache, in der Funktionen nur so verwendet werden können, wie sie ursprünglich verwendet werden sollten. Eine solche Sprache wäre so begrenzt, dass es fraglich ist, ob sie überhaupt für die Programmierung in der realen Welt verwendet werden kann.


4
Die Protokollierung scheint ein spezifisches Beispiel zu sein, bei dem AOP nicht zu einer Aktion auf Distanz führt. Zu diesem Zeitpunkt ist Wikipedia das Beispiel für die Verwendung von Aspekten für Dinge wie Sicherheitsüberprüfungen, die den Programmfluss so viel verständlicher machen.
kizzx2

7
@ kizzx2: Tatsächlich ein großartiger Punkt beim Protokollieren - es ist das beste Beispiel, das ich bisher für die Stärke von AOP gesehen habe, ohne zu viel über AOP zu wissen. Danke für das Teilen!
Fehler

@Mecki, Ihr Beispiel ist zu stark vereinfacht und spiegelt nicht den allgemeinen Anwendungsfall wider. Nimmt in Ihrem Beispiel Display.updatekeine Argumente an. Was ist, wenn wir Argumente übergeben müssen (z. B. logwürde eine Funktion normalerweise einen messageParameter erfordern )? Müssten wir dann nicht eine Menge Boilerplate-Code hinzufügen, um dies auf AOP-Weise zu tun?
Pacerier

3
@ Pacerier Mein Beispiel ist vereinfacht, weil SO kein Lehrforum ist. Ich beantwortete nur die Frage des Fragestellers, wahrscheinlich weitaus detaillierter als nötig. Wenn Sie mehr über AOP erfahren möchten, lesen Sie die Dokumentation des Programmierers. Wenn Sie eine detaillierte Frage haben, stellen Sie diese bitte hier. Nein, nicht in einem Kommentar, geht und eine neue Frage , weil das ist , was so geht. Ich bin sicher, dass jemand Ihre Zweifel in einer Antwort zerstreuen kann.
Mecki

2
@ Pacerier Entschuldigung, aber ich verstehe Ihren Standpunkt nicht. Siehe hier: stackoverflow.com/a/8843713/15809 Dieser Code protokolliert jeden Aufruf jeder öffentlichen Methode, einschließlich aller Methodenargumenttypen und -werte. Sie schreiben dies genau einmal und jeder Methode wird kein Boilerplate-Code hinzugefügt. Es ist nur der Code, der in der Antwort angezeigt wird.
Mecki

29

Die aspektorientierte Programmierung bietet eine gute Möglichkeit, Querschnittsthemen wie Protokollierung und Sicherheit umzusetzen. Diese übergreifenden Aspekte sind logische Elemente, die an vielen Stellen angewendet werden müssen, aber eigentlich nichts mit der Geschäftslogik zu tun haben.

Sie sollten AOP nicht als Ersatz für OOP sehen, sondern eher als ein nettes Add-On, das Ihren Code sauberer, lockerer und auf die Geschäftslogik fokussierter macht. Wenn Sie AOP anwenden, erhalten Sie zwei wesentliche Vorteile:

  1. Die Logik für jedes Problem befindet sich jetzt an einem Ort, anstatt über die gesamte Codebasis verteilt zu sein.

  2. Klassen sind sauberer, da sie nur Code für ihr primäres Anliegen (oder ihre Kernfunktionalität) enthalten und sekundäre Anliegen zu Aspekten verschoben wurden.


27

OOP und AOP schließen sich nicht gegenseitig aus. AOP kann eine gute Ergänzung zu OOP sein. AOP ist besonders praktisch, um Methoden Standardcode wie Protokollierung, Leistungsverfolgung usw. hinzuzufügen, ohne den Methodencode mit diesem Standardcode zu verstopfen.


10

Ich denke, es gibt keine allgemeine Antwort auf diese Frage, aber eine Sache, die beachtet werden muss, ist, dass AOP OOP nicht ersetzt, sondern bestimmte Zerlegungsmerkmale hinzufügt, die die sogenannte Tyrannei der dominanten Komposition ( 1 ) (oder Querschnittsthemen) ansprechen .

In bestimmten Fällen hilft es sicherlich, solange Sie die Kontrolle über die Tools und Sprachen haben, die für ein bestimmtes Projekt verwendet werden sollen, aber es fügt auch eine neue Komplexität hinsichtlich der Interaktion von Aspekten hinzu und die Notwendigkeit, zusätzliche Tools wie das AJDT noch zu verstehen Ihr Programm.

Gregor Kiczales hielt einmal einen interessanten Einführungsvortrag zu AOP bei Google Tech Talks, den ich empfehlen sollte: Aspektorientierte Programmierung: Radikale Forschung in Modularität .


8

Erstens wird AOP OOP nicht ersetzen. AOP erweitert OOP. Die Ideen und Praktiken von OOP bleiben relevant. Ein gutes Objektdesign wird es wahrscheinlich einfacher machen, es um Aspekte zu erweitern.

Ich denke, die Ideen, die AOP bringt, sind wichtig. Wir müssen Wege finden, um Querschnittsthemen für verschiedene Klassen in Ihrem Programm umzusetzen, ohne die Klassen selbst ändern zu müssen. Aber ich denke, das AOP wird irgendwann nur noch Teil anderer Tools sein, die wir verwenden, und nicht eines separaten Tools oder einer separaten Technik. Wir sehen dies bereits.

Einige dynamische Sprachen wie Ruby und Python haben Sprachkonstrukte wie Mixins, die dieselben Probleme lösen. Dies sieht AOP sehr ähnlich, ist aber besser in die Sprache integriert.

Spring and Castle und einige andere Abhängigkeitsinjektions-Frameworks bieten Optionen zum Hinzufügen von Verhalten zu den Klassen, die sie injizieren. Dies ist eine Möglichkeit, Laufzeitweberei zu betreiben, und ich denke, dies hat viel Potenzial.

Ich glaube nicht, dass Sie ein völlig neues Paradigma lernen müssen, um AOP zu verwenden. Die Ideen sind interessant, werden aber langsam von vorhandenen Tools und Sprachen aufgenommen. Bleiben Sie einfach auf dem Laufenden und probieren Sie diese Tools aus.



1

Ich bin spät dran, um diese Frage zu beantworten, aber sie ist eines meiner Lieblingsthemen. Lassen Sie mich meine Ansicht teilen.

OOP wird hauptsächlich zum Organisieren Ihrer Geschäftslogik verwendet, während AOP beim Organisieren Ihrer nicht funktionalen Dinge wie Auditing, Protokollierung, Transaktionsmanagement, Sicherheit usw.

Auf diese Weise können Sie Ihre Geschäftslogik mit einer nicht fiktiven Logik entkoppeln, die den Code sauberer macht.

Ein weiterer Vorteil ist, dass Sie die Ratschläge (Beispielprüfung) sehr konsistent anwenden können, ohne eine Schnittstelle zu implementieren, die eine große Flexibilität für Änderungen bietet, ohne die Geschäftslogik zu berühren

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.