Der erste Teil des Buches "Software Sanierung" von Sebastian Kübeck beinhaltet eine umfangreiche Auswahl von
Gang-Of-Four Entwurfsmustern inklusive guter Code-Beispiele. Die gewählten Patterns sind nach Ansicht des Autors "für das Sanieren" sinnvoll.
Nachdem ich auf meiner letzten Reise (nicht Urlaub) das Orginal-Gang-Of-Four Buch brav neben dem Bett liegen hatte, in der Hoffnung, dass sich Erkenntnisse daraus automatisch im Schlaf in Richtung meines Gehirns bewegen, habe ich hier die Chance ergriffen und die vorgestellten Muster im klassichen Schulprinzip durchgearbeitet. Dies sind meine Hefter-Notizen:
Abstrakte Fabrik
Klassisch wird ein Objekt mit "new" erzeugt. Eine
Abstrakte Fabrik ist eine Klasse oder Interface, die mindestens eine Methode hat, die ein Objekt erzeugt.
Schablonenmethode/ Template Method
Ein
Algorithmus wird in einer abstrakten Klasse definiert, wobei die
Implementierung von Algorithmus-Details an Unterklassen ausgelagert
wird. Zusätzlich kann die abstrakte Klasse auch noch leere
Zwischenschrittsmethoden haben, die in Unterklassen optional
implemenitert werden können.
Wert-Objekt
"Ein Wertobjekt ist dadurch gekennzeichnet, dass seine Identität von den Werten bestimmt wird aus denen es aufgebaut ist."
Es hat keine eigene Identität. Im Buch wird noch darauf verwiesen, dass
ein Kennzeichen von Java-Wertobjekten die Implementierung der Methoden
"hashCode" und "equals" sind durch die der Programmierer einen
Mechanismus zum Inhalts-Vergleich anbietet.
Ein Wertobjekt ist nach seiner Erstellung nicht mehr veränderbar (
immutable).
Das Wert-Objekt ist nicht zu verwechseln mit dem auch in Javascript sehr populären "Data Transfer Objekt".
Null-Objekt
"Provide
an object as a surrogate for the lack of an object of a given type. The
Null Object Pattern provides intelligent do nothing behavior, hiding
the details from its collaborators."
Im Buch wird ein Beispiel angeführt wo, abhängig von einem Konstruktor-Parameter, eine Ausgabe auf
OutputStream-Objekt
erfolgen soll - oder, wenn der Parameter "null" ist, anstelle dessen
die Ausgabe über die Null-Objekt Implementierung von
OutputStream.
Stellvertreter (Proxy)
Ein
Objekt welches seine Methodenaufrufe an sein Orginal-Objekt
weiterleitet. Stellvertreter und Orginal implementieren das gleiche
Interface. Zusätzlich erfolgen aber noch weiter Aktionen im
Stellvertreter die im Orginal nicht erfolgen.
Beispiel ist das
Anklemmen von Logging. Dem Orginal-Objekt fehlt das Logging, der
Stellvertreter besitzt die gleiche Signatur wie das Orginal, leitet die
Methodenaufrufe auch an das Orginal weiter - aber loggt noch zusätzlich.
Adapter
Wie
"Stellvertreter" allerdings underscheiden sich Methodensignatur von
Orginal und Adapter Objekt. Dient als Verbindungsstück zwischen zwei
verschiedenen Interfaces.
Beobachter
Häufig
genutzt für Event-Handling in einer GUI. Die Beispiele im Buch haben
aber eine andere Ausrichtung: Einem zu beobachtenten Objekt wird z.B. im
Konstruktor ein Beobachter-Objekt übergeben. Dieser Beobachter könnte
z.B. ein Logging implementieren.
An geeigneter Stelle werden dann im Orginal-Objekt die Beobachter-Methoden aufgerufen die dann z.B. zu einem Log-Eintrag führen.
Das
Pattern ist praktisch für das testbar-machen von Log-Einträgen: Es gibt
für das Beobachter-Objekt eine Produktiv-Implementierung, die einfach
auf STDOUT schreibt und eine Test-Implementierung die sich zusätzlich
das geloggte im Objekt merkt. Ein Unittest kann dann das "gemerkte"
(z.B. eine Liste) vergleichen.
Dem zu beobachtenden Objekt (das mit der Fachlogik) wird dann der jeweilig passende Beobachter übergeben.
Fascade
Gang-of-Four Definition:
"Biete
eine einheitliche Schnittstelle zu einer Menge von Schnittstellen eines
Subsystems. Die Fassadenklasse definiert eine abstrakte Schnittstelle,
welche die Verwendung des Subsystems vereinfacht." (Erich Gamma,
Richard Helm, Ralph Johnson, John Vlissides: "Entwurfsmuster. Elemente
wiederverwendbarer objektorientierter Software". Addison-Wesley. 1.
Auflage 1996, S. 212)
Kommando
Kapsselung
von Befehlen in ein Objekt. Im Buch wird ein Beispiel für einen
einfachen Dateimanager gebracht. Die Hauptklasse (der FileManager)
empfängt die Befehle als Arguments und ruft dann das entsprechende
Kommando-Objekt auf. Die konkreten Aktionen zu einem Befehl sind im
Objekt gekapselt.
Eine Erweiterung des Programmes ist einfach, es
wird ein neues Kommando-Objekt angelegt (und getestet), dann wird der
Hauptklasse noch das neue Objekt bekannt gegeben.
Strategie
Ein
alter Bekannter im neuen Kleid, auch eine Anwendung des
Abhängigkeits-Inversionsprinzips. Die Idee ist, Algorithmen die einer
häufigen Änderung unterliegen via Interface zu implementieren. und
damit einfacher ausstauschbar zu machen.
Das Buch führt
als Beispiel einen einfachen Passwort-Authenticator an. Die
Passwort-Policy ist veränderlichen organisatorischen Regeln ausgesetzt -
aus diesem Grund wird sie mittels Strategy-Pattern implementiert.
Konkret
gibt es ein "PasswordPolicy" Interface welches nur die Methode
"isSecure()" beinhaltet. Da die Frage "isSecure()" organisatorischen
Änderungen unterworfen ist, wird die konkrete Implementierung von
"PasswordPolicy" regelmäßig angepasst in dem eine neue Klasse
geschrieben wird.
Die Authenticator-Hauptklasse bekommt im Konstruktor nur die jeweilig aktuelle Implementierung der Policy übergeben.