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.