Einführung
Ich implementiere eine abstrakte Java-Klasse eines Verarbeitungsframeworks *. Durch die Implementierung der Funktion execute
kann ich geschäftslogische Funktionen hinzufügen. Ich möchte die Protokollierung zu Beginn und am Ende jeder Implementierung jeder meiner Ausführungsfunktionen hinzufügen. Auch zwischen einigen Protokollierungen, wenn bestimmte Dinge erledigt werden. Ich möchte dies jedoch einheitlich gestalten. Mein Gedanke war, die Framework-Klasse an eine eigene neue Klasse zu erben, die die Protokollierung implementiert und einige neue executeWithLogging
Funktionen bereitstellt , die die Protokollierung um die spezifischen Teile wickeln. Ich bin mir nicht sicher, ob das die beste Idee ist und ob ich ein Designmuster verwenden kann, das das ganze Unternehmen elegant macht. Wie würde ich mit der ganzen Sache weitermachen?
Herausforderungen (bitte beachten Sie diese!)
- Eine Herausforderung in meinem Fall ist, dass die ursprüngliche Klasse nur eine
execute
Funktion hat, ich jedoch mehrere Teile protokollieren müsste. - Die zweite Sache ist: Unter Verwendung eines Decorator - Muster (war meine erste Idee auch) nicht ganz funktioniert, wenn ich auch benutze
execute
, weil diesuper.execute()
-function in der ersten Zeile meines neuen genannt werden müsstenexecute()
, ist es nicht ? - Es wären mindestens 4 Klassen beteiligt:
BaseFunction
vom Rahmen,LoggingFunction extends BaseFunction
von mir,MyBusinessFunction extends LoggingFunction
von mir,MyBusinessClass
der instanziiertMyBusinessFunction
. - Ich muss mich nicht nur am Anfang und am Ende von
execute
, sondern auch in der Mitte anmelden. - Die "Protokollierung" ist nicht nur eine einfache Java-Protokollierung, sondern eine Protokollierung in einer Datenbank. Dies ändert nichts an den Prinzipien, zeigt jedoch, dass die Protokollierung mehr als nur eine Codezeile sein kann.
Vielleicht wäre ein Beispiel, wie ich das Ganze machen würde, schön, um mich zum Laufen zu bringen.
| * Eine Storm Trident-Funktion, ähnlich einem Storm-Bolzen, aber dies ist nicht besonders wichtig.
quelle
execute
inBaseFunction
abstrakt?execute
ist abstrakt inBaseFunction
.Antworten:
Im Allgemeinen gibt es mehrere Möglichkeiten, eine bestimmte Ausführung zu protokollieren. Zunächst ist es gut, dass Sie dies trennen möchten, da die Protokollierung ein typisches Beispiel für die Trennung von Bedenken ist . Es macht wirklich wenig Sinn, die Protokollierung direkt in Ihre Geschäftslogik aufzunehmen.
In Bezug auf mögliche Entwurfsmuster ist hier eine (nicht schlüssige) Liste von oben:
Dekorationsmuster : Ein bekanntes Entwurfsmuster, bei dem Sie die nicht protokollierende Klasse grundsätzlich in eine andere Klasse derselben Schnittstelle einbinden und der Wrapper die Protokollierung vor und / oder nach dem Aufruf der umschlossenen Klasse durchführt.
Funktionszusammensetzung : In einer funktionalen Programmiersprache können Sie Ihre Funktion einfach mit einer Protokollierungsfunktion zusammenstellen. Dies ähnelt dem Dekorationsmuster in OO-Sprachen, ist jedoch keine bevorzugte Methode, da die zusammengesetzte Protokollierungsfunktion auf einer nebenwirkenden Implementierung basieren würde.
Monaden : Monaden stammen ebenfalls aus der Welt der funktionalen Programmierung und ermöglichen es Ihnen, Ihre Ausführung und Protokollierung zu entkoppeln. Dies bedeutet im Grunde, dass Sie die erforderlichen Protokollierungsnachrichten und Ausführungsmethoden zusammenfassen, aber auch noch nicht ausführen. Sie können dann die Monade verarbeiten, um das Schreiben von Protokollen und / oder die tatsächliche Ausführung der Geschäftslogik durchzuführen.
Aspektorientierte Programmierung : Anspruchsvollerer Ansatz, der eine vollständige Trennung erreicht, da die Klasse, die das Nichtprotokollierungsverhalten ausführt, niemals direkt mit der Protokollierung interagiert.
Weiterleitung: Möglicherweise sind auch andere Standardentwurfsmuster geeignet. Beispielsweise kann eine Fassade als protokollierter Einstiegspunkt dienen, bevor der Anruf an eine andere Klasse weitergeleitet wird, die den Geschäftslogikteil ausführt. Dies kann auch auf verschiedene Abstraktionsebenen angewendet werden. Beispielsweise können Sie Anforderungen an eine extern erreichbare Dienst-URL protokollieren, bevor Sie sie an eine interne URL weiterleiten, um sie tatsächlich nicht protokolliert zu verarbeiten.
Was Ihre zusätzliche Anforderung betrifft, dass Sie die Protokollierung "in der Mitte" durchführen müssen, deutet dies wahrscheinlich auf ein seltsames Design hin. Warum tut Ihre Ausführung so viel, dass so etwas wie eine "Mitte" ihrer Ausführung auch nur aus der Ferne von Interesse ist? Wenn tatsächlich so viel los ist, warum nicht in Phasen / Phasen / Was-hast-du? Theoretisch könnte man mit AOP eine Protokollierung in der Mitte erreichen, aber ich würde trotzdem argumentieren, dass eine Designänderung viel angemessener erscheint.
quelle
Ich habe das Gefühl, dass Sie unbedingt ein Muster verwenden möchten. Denken Sie daran, dass eine schlechte Verwendung von Entwurfsmustern dazu führen kann, dass der Code weniger wartbar / lesbar ist.
Das heißt ...
Ihr Fall ist schwierig, da Sie anscheinend zwei Arten der Protokollierung durchführen möchten:
execute
)execute
)Für den ersten Fall müssen Sie im Moment, in dem Sie einige Dinge innerhalb einer Funktion protokollieren möchten, dies tun ... innerhalb der Funktion. Sie könnten das Muster der Vorlagenmethode verwenden, um die Dinge etwas hübscher zu machen, aber ich denke, es ist in diesem Fall übertrieben .
Für den zweiten Fall ist das Dekorationsmuster der richtige Weg:
Und Sie könnten es so verwenden in
BusinessClass
:Ein Anruf bei
doFunction
protokolliert dies:quelle
super.execute();
stattorigin.execute();
?super.execute()
diese Methode aufrufenabstract
?Ihr Ansatz scheint gültig zu sein und ist tatsächlich eine Implementierung des Decorator-Musters . Es gibt andere Möglichkeiten, wie Sie dies tun können, aber Decorator ist ein sehr elegantes und leicht verständliches Muster, das sich sehr gut zur Lösung Ihres Problems eignet.
quelle
Wie wäre es mit dem Befehlsmuster?
quelle
execute()
Tun Sie im Moment auch nichts, da Sie nur instanziierenMyLoggingCommandWhole
.MyLoggingCommandWhole
, ausgeführtexecuteWithoutLogging();
vonMyLoggingCommandWhole
. Ist das nicht der Fall?MyLoggingCommandWhole cmd = new MyLoggingCommandWhole() { ... }; cmd.executeWithoutLogging();
executeWithLogging()
und einfügencmd.executeWithLogging()
. Immerhin sollte das ausgeführt werden.