Verhaltensmuster

Befehl (Command)

Zweck: Kapsle einen Befehl als ein Objekt. Dies ermöglicht es, Klienten mit verschiedenen Anfragen zu parametrisieren, Operationen in eine Queue zu stellen, ein Logbuch zu führen und Operationen rückgängig zu machen.
Struktur: Befehl
Abb. 3.1 Befehl
Teilnehmer:

  • Befehl
    • deklariert eine Schnittstelle zum Ausführen einer Operation
  • KonkreterBefehl
    • definiert die Anbindung eines Empfängers an eine Aktion.
    • implementiert FuehreAus durch Aufrufen der entsprechenden Operation(en) beim Empfänger.
  • Klient
    • erzeugt ein KonkreterBefehl-Objekt und übergibt ihm den Empfänger.
  • Auslöser
    • befiehlt dem Befehlsobjekt, die Anfrage auszuführen.
  • Empfänger
    • weiß, wie die an die Ausführung einer Anfrage gebundenen Operationen auszuführen sind. Jede Klasse kann ein Empfänger sein.

Anwendbarkeit: Verwenden sie das Befehlsmuster, wenn Sie

  • Objekte mit einer auszuführenden Aktion parametrieren wollen, so wie es mit dem MenueEintrag (siehe Buch) gemacht worden ist. Sie können eine derartige Parametrisierung in einer prozeduralen Sprache mit einer Callback-Funktion erreichen. Dies ist eine Operation, die man irgendwo registriert und die zu einem späteren Zeitpunkt aufgerufen wird. Befehlsobjekte sind ein objektorientierter Ersatz für Callbacks.
  • Anfragen zu unterschiedlichen Zeitpunkten spezifizieren, aufreihen und ausführen lassen wollen. Ein Befehlsobjekt kann über eine von der ursprünglichen Anfrage unabhängige Lebensdauer verfügen. Wenn der Empfänger einer Anfrage in einer vom Adressraum unabhängigen Weise repräsentiert werden kann, dann können Sie ein Befehlsobjekt für die Anfrage zu einem anderen Prozess transferieren und die Anfrage dort ausführen lassen.
  • Undo, also das Rückgängigmachen von Operationen, unterstützen wollen. Die FuehreAus- Operation einer Befehlsklasse kann den relevanten Zustand für die Umkehr des Befehls im Befehlsobjekt selbst speichern. Die Befehlsklassenschnittstelle muss dann über eine zusätzliche Rückgängig-Opertion verfügen, welche die Auswirkung des vorigen FuehreAus-Aufrufs rückgängig macht. Einmal ausgeführte Befehlsobjekte werden in einer Befehlsgeschichte (einer Liste) gespeichert. Unbegrentztes Undo und Redo erreicht man durch Traversieren der Liste vorwärts und rückwärts, wobei man jeweils FuehreAus respektive Rückgängig aufruft.
  • das Mitprotokollieren von Änderungen unterstützen wollen, so dass Sie im Falle eines Absturtzes nach diesem erneut ausgeführt werden können. Indem Sie die Befehlsklassenschnittstelle um Operationen zum Laden und Speichern erweitern, können Sie ein persistentes Logbuch der Änderungen anlegen. Das System nach einem Absturz wieder herzustellen umfasst dann das Laden von gespeicherten Befehlsobjekten von der Platte und ihre erneute Ausführung mittels der FuehreAus-Operation.
  • ein System mittels komplexer Operationen strukturieren wollen, die aus primitiven Operationen aufgebaut werden. Soch eine Struktur kann oft in Informationssystemen gefunden werden, die Transaktionen unterstützen. Eine Transaktion kapselt eine Menge von Datenänderungen. Das Befehlsmuster stellt eine Möglichkeit dar, Transaktionen zu modellieren. Befehlsobjekte besitzen eine gemeinsame Schnittstelle, die es ihnen ermöglicht, alle Transaktionen auf die gleiche Weise aufzurufen. Das Muster erleichtert es zudem, das System um neue Transaktionen zu erweitern.


Beobachter (Observer)

Zweck: Definiere eine 1-zu-n-Abhängigkeit zwischen Objekten, so dass die Änderung des Zustands eines Objekts dazu führt, dass alle abhängigen Objekte benachrichtigt und automatisch aktualisiert werden.
Struktur: Beobachter
Abb. 3.2 Beobachter
Teilnehmer:

  • Subjekt
    • kennt seine Beobachter. Eine beliebige Anzahl von Beobachtern kann ein Subjekt beobachten.
    • bietet eine Schnittstelle zum An- und Abmelden von Beobachtern.
  • Beobachter
    • definiert eine Aktualisierungsschnittstelle für Objekte, die über Änderungen eines Subjekts benachrichtigt werden sollen.
  • KonkretesSubjekt
    • speichert den für KonkreteBeobachter relevanten Zustand.
    • benachrichtigt seine Beobachter, wenn sich sein Zustand ändert.
  • KonkreterBeobachter
    • verwalter eine Referenz auf ein KonkretesSubjekt.
    • speichert den Zustand, der mit dem des Subjekts in Einklang stehen soll.
    • implementiert die Aktualisierungsschittstelle

Anwendbarkeit: Verwenden sie das Beobachtermuster in jeder der folgenden Situationen:

  • Wenn eine Abstraktion zwei Aspekte besitzt, von denen der eine von dem anderen abhängt. Die Kapselung dieser Aspekte in unterschiedlichen Objekten ermöglicht es Ihnen, sie zu variieren und sie unabhängig voneinander wiederzuverwenden.
  • Wenn die Änderung eines Objekts die Änderung anderer Objekte verlangt und Sie nicht wissen, wie viele Objekte geändert werden müssen.
  • Wenn ein Objekt in der Lage sein sollte, andere Objekte zu benachrichtigen, ohne Annahmen darüber treffen zu dürfen, wer diese anderen Objekte sind.
    Mit anderen Worten: Sie wollen diese Objekte nicht eng miteinander koppeln.


Besucher (Visitor)

Zweck: Kapsle eine auf den Elementen einer Objektstruktur auszuführende Operation als ein Objekt. Das Besuchermuster ermöglicht es Ihnen, eine neue Operation zu definieren, ohne die Klassen der von ihr bearbeiteten Elemente zu verändern.
Struktur: Besucher
Abb. 3.3 Besucher
Teilnehmer:

  • Besucher
    • deklariert eine Besuche-Operation für jede KonkretesElement-Klasse in der Objektstruktur. Der Operationsname und seine Signatur benennen die Klasse, welche die Besuche-Operation des Besuchers aufruft. Dies ermöglicht es dem Besucher, die konkrete Klasse des besuchten Elements zu bestimmen. Der Besucher kann dann unter Verwendung der konkreten Schnittstelle auf das Element zugreifen.
  • KonkreterBesucher
    • implementiert jede von der Besucherklasse deklarierte Operation. Jede Operation implementiert ein Fragment des für die entsprechende Klasse des Objekts einer Struktur definierten Algorithmus. Ein KonkreterBesucher liefert den Kontext für den Algorithmus und speichert seinen lokalen Zustand. Dieser Zustand enthält häufig die während der Traversierung der Struktur angesammelten Ergebnisse.
  • KonkretesElement
    • implementiert eine NimmEntgegen-Operation, die einen Besucher als Argument empfangen kann.
  • ObjektStruktur
    • kann seine Elemente aufzählen.
    • bietet möglicherweise eine abstrakte Schnittstelle, die es dem Besucher erlaubt, seine Elemente zu besuchen.
    • kann gleichermaßen ein Kompositum oder ein Behälter wie zum Beispiel eine Liste oder eine Menge sein.

Anwendbarkeit: Verwenden sie das Besuchermuster, wenn

  • eine Objektstruktur viele Klassen von Objekten mit unterschiedlichen Schnittstellen enhält und Sie Operationen auf diesen Objekten ausführen wollen, die von ihren konkreten Klassen abhängen.
  • viele unterschiedliche und nicht miteinander verwandte Operationen auf den Objekten einer Objektstruktur ausgeführt werden müssen und Sie es vermeiden wollen, Ihre Klassen mit diesen Operatioen zu "verschmutzen". Das Besuchermuster ermöglicht es ihnen, die verwandten Operationen beisammen zu halten, indem Sie sie in einer einzigen Klasse definieren. Wenn die Objektstruktur von mehreren Anwendungen gemeinsam genutzt wird, sollten sie das Besuchermuster verwenden, um Operationen nur in jenen Anwendungen zu verwenden, die sie wirklich benötigen.
  • sich die Klassen, die eine Objektstruktur definieren, praktisch nie ändern, Sie aber häufig neue Operationen für die Struktur definieren wollen. Das Ändern der Klassen der Objektstruktur führt zur Neudefinition der Schnittstellen aller Besucherklassen, was sehr teuer sen kann. Wenn sich die Objektstruktur häufig ändert, ist es wahrscheinlich besser, die Operationen in diesen Klassen zu definieren.


Interpreter (Interpreter)

Zweck: Definiere für eine gegebene Sprache eine Repräsentation der Grammatik sowie einen Interpreter, der die Repräsentation nutzt, um Sätze in der Sprache zu interpretieren.
Struktur: Interpreter
Abb. 3.4 Interpreter
Teilnehmer:

  • AbstrakterAusdruck
    • deklariert eine abstrakte Interpretiere-Operation, die allen Knoten im abstrakten Syntaxbaum gemien ist.
  • TerminalAusdruck
    • implementiert die Interpretiere-Operation, die mit den Terminalsymbolen in der Grammatik verbunden ist.
    • für jedes Terminalsymbol in einem Satz wird ein Exemplar dieser Klasse benötigt.
  • NichtTerminalausdruck
    • pro Regel R ::= R1 R2 ... Rn in der Grammatik wird eine derartige Klasse benötigt.
    • verwaltet Exemplarvariablen des Typs AbstrakterAusdruck für jedes der Symbole R1 bis Rn
    • implementiert eine Interpretiere-Operation für Nichtteminalsymbole der Grammatik. Interpretiere ruft üblicherweise sich selbst rekursiv auf den Variablen auf, die R1 bis Rn repräsentieren.
  • Kontext
    • enthält dir für den Interpreter globalen Informtionen.
  • Klient
    • konstruiert (oder enthält) einen abstrakten Syntaxbaum, der einen bestimmten Satz in der von der Grammatik definierten Sprache repräsentiert. Der abstrakte Syntaxbaum wird aus den Exemplaren der NichtTerminalAusdruck- und TerminalAusdruck-Klassen zusammengesetzt.
    • ruft die Interpretiere-Operation auf.

Anwendbarkeit: Verwenden sie das Interpretermuster, wenn sie eine Sprache interpretieren müssen und Sie die Ausdrücke der Sprache als abstrakte Syntaxbäume darstellen können. Das Interpretermuster funktioniert am Besten, wenn

  • die Grammatik einfach ist. Angesichts komplexer Grammatiken wird die Klassenhierarchie zu groß und nicht mehr handhabbar. In diesem Fall stellen Werkzeuge wie Parsergeneratoren eine bessere Alternative dar. Sie können Ausdrücke ohne den Aufbau abstrakter Syntaxbäume interpretieren, was Speicherplatz und möglicherweise auch Zeit kostet.
  • die Effizienz unproblematisch ist. Die effizientesten Interpreter werden üblicherweise nicht durch die Interpretation von Parserbäumen implementiert; sie transformieren die Bäume statt dessen in eine andere Form. Reguläre Ausdrücke werden beispielsweise oft in Zustandsautomaten transformiert. Aber selbst unter diesen Umständen kann der Übersetzer immer noch mit Hilfe des Interpretermusters implementiert werden, so dass das Muster immer noch anwendbar ist.


Iterator (Iterator)

Zweck: Ermögliche den sequentiellen Zugriff auf die Elemente eines zusammengesetzten Objekts, ohne seine zugrundeliegende Repräsentation offenzulegen.
Struktur: Iterator
Abb. 3.5 Interator
Teilnehmer:

  • Iterator
    • definiert eine Schnittstelle zum Zugriff auf und zur Traversierung von Elementen.
  • KonkreterIterator
    • implementiert die Schnittstelle von Iterator.
    • verwaltet die aktuelle Position während der Traversierung des Aggregats.
  • Aggregat
    • definiert eine Schnittstelle zum Erzeugen eines Objekts der Klasse Iterator.
  • KonkretesAggregat
    • implementiert die Operation zum Erzeugen eines konkreten Iterators, in dem es ein Objekt der passenden KonkreterIterator-Klasse zurückgibt.

Anwendbarkeit: Verwenden Sie das Iteratormuster

  • um den Zugriff auf den Inhalt eines zusammengesetzten Objekts zu ermöglichen, ohne dabei seine interne Struktur offenzulegen.
  • um mehrfache gleichzeitige Traversierungen auf zusammengesetzten Objekten zu ermöglichen.
  • um eine einheitliche Schittstelle zur Traversierung unterschiedlicher zusammengesetzter Strukturen anzubieten (das heißt, um polymorphe Interation zu ermöglichen).


Memento (Memento)

Zweck: Erfasse und externalisiere den internen Zustand eines Objekts, ohne seine Kapselung zu verletzen, so dass das Objekt später in diesem Zustand zurückversetzt werden kann.
Struktur: Memento
Abb. 3.6 Memento
Teilnehmer:

  • Memento
    • speichert internen Zustand des Urheberobjekts. Das Memento kann soviel oder so wenig vom internen Zustand des Urhebers zwischenspeichern wie es nach eigenem Gutdünken benötigt.
    • schützt sich gegen Zugriff durch andere Objekte außer dem Urheber. Mementos besitzen effektiv zwei Schnittstellen. Der Aufbewahrer sieht vom Memento nur eine schmale Schnittstelle - er kann das Memento nur an andere Objekte weitergeben. Der Urheber sieht im Gegensatz dazu eine breite Schnittstelle, die es ihm ermöglicht, auf alle benötigten Daten zuzugreifen, um sich selbst in seinen vorigen Zustand zurückzuversetzen. Idealerweise kann nur der Urheber, der das Memento erzeugt hat, auf den internen Zustand des Mementos zugreifen.
  • Urherber
    • erzeugt ein Memento, das eine Momentaufnahme seines aktuellen internen Zustands enthält.
    • verwendet das Memento, um seinen internen Zustand wieder herzustellen.
  • Aufbewahrer
    • ist für die Aufbewahrung des Mementos zuständig.
    • arbeitet niemals mit dem Inhalt des Mementos oder untersucht es.

Anwendbarkeit: Verwenden Sie das Mementomuster, wenn

  • eine Momentaufnahme (eines Teils) des Zustands eines Objekts zwischengespeichert werden muss, so dass es zu einem späteren Zeitpunkt in diesen Zustand zurückversetzt werden kann, und wenn
  • eine direkte Schnittstelle zum Ermitteln des Zustands die Implementierungsdetails offenlegen und die Kapselung des objekts aufbrechen würde.


Schablonenmethode (Template Method)

Zweck: Definiere das Skelett eines Algorithmus in einer Operation und delegiere einzelne Schritte an Unterklassen. Die Verwendung einer Schablonenmethode ermöglicht es Unterklassen, bestimmte Schritte eines Algorithmus zu überschreiben, ohne seine Struktur zu verändern.
Struktur: Schablonenmethode
Abb. 3.7 Schablonenmethode
Teilnehmer:

  • AbstrakteKlasse
    • definiert abstrakte promitive Operationen, die von konkreten Unterklassen definiert werden, um die Schritte eines Algorithmus zu implementieren.
    • implementiert eine Schablonenmethode zur Definition des Skeletts eines Algorithmus. Die Schablonenmethode ruft sowohl primitive Operationen als auch in AbstrakteKlasse oder anderen Klassen definierte Operationen auf.
  • KonkreteKlasse
    • implementiert die primitiven Operationen, welche die unterklassenspezifischen Schritte des Algorithmus ausführen.

Anwendbarkeit: Eine Schablonenmethode sollte verwendet werden,


Strategie (Strategy)

Zweck: Definiere eine Familie von Algorithmen, kapsle jeden einzelnen und mache sie austauschbar. Das Strategiemuster ermöglicht es, den Algorithmus unabhängig von ihn nutzenden Klienten zu variieren.
Struktur: Strategie
Abb. 3.8 Strategie
Teilnehmer:

  • Strategie
    • deklariert eine Schnittstelle, die von allen unterstützten Algorithmen angeboten wird. Das Kontextobjekt verwendet diese Schnittstelle, um den durch eine KonkreteStrategie definierten Algorithmus aufzurufen.
  • KonkreteStrategie
    • implementiert den Algorithmus unter Verwendung der Strategieschnittstelle.
  • Kontext
    • wird mit einem KonkretenStrategie-Objekt konfiguriert.
    • verwaltet eine Referenz auf ein Strategieobjekt.
    • kann eine Schnittstelle definieren, die Strategieobjekten den Zugriff auf seine Daten ermöglicht.

Anwendbarkeit: Verwenden Sie das Strategiemuster, wenn


Vermittler (Mediator)

Zweck: Definiere ein Objekt, welches das Zusammenspiel einer Menge von Objekten in sich kapselt. Vermittler fördern lose Kopplung, indem sie Objekte davon abhalten, aufeinander explizit Bezug zu nehmen. Sie ermöglichen es Ihnen, das Zusammenspiel der Objekte von ihnen unabhängig zu variieren.
Struktur: Vermittler
Abb. 3.9 Vermittler
Teilnehmer:

  • Vermittler
    • definiert eine Schnittstelle für die Interaktionen mit Kollegen-Objekten.
  • KonkreterVermittler
    • implementiert das Gesamtverhalten durch Koordination der Kollegen-Objekte.
  • Kollegen-Klassen
    • jede Kollegen-Klasse kennt ihre Vermittler-Klasse.
    • jedes Kollegen-Objekt arbeitet mit seinem Vermittler zusammen, statt dies mit seinen Kollegen-Objekten zu tun.

Anwendbarkeit: Verwenden Sie das Vermittlermuster, wenn

  • Sie eine Menge von Objekten vorliegen haben, die in wohldefinierter, aber komplexer Weise miteinander zusammenarbeiten. Die sich ergebenden Abhängigkeiten sind unstrukturiert und schwer zu verstehen.
  • die Wiederverwendung eines Objekts schwierig ist, weil es sich auf viele andere Objekte bezieht und mit ihnen zusammenarbeitet.
  • ein auf mehrere Klassen verteiltes Verhalten maßgeschneidert werden können sollte, ohne viele Unterklassen bilden zu müssen.


Zustand (State)

Zweck: Ermögliche es einem Objekt, sein Verhalten zu ändern, wenn sein interner Zustand sich ändert. Es wird so aussehen, als ob das Objekt sein Klasse gewechselt hat.
Struktur: Zustand
Abb. 3.10 Zustand
Teilnehmer:

  • Kontext
    • definiert die Klienten interessierende Schnittstelle.
    • verwaltet ein Exemplar einer KonkreterZustand-Unterklasse, welche den aktuellen Zustand definiert.
  • Zustand
    • definiert eine Schnittstelle zur Kapselung des mit einem bestimmten Zustand des Kontextobjekts verbundenen Verhaltens.
  • KonkreterZustand-Unterklassen
    • jede Unterklasse implementiert ein Verhalten, das mit einem Zustand des Kontextobjekts verbunden ist.

Anwendbarkeit: Verwenden Sie das Zustandsmuster in einem der folgenden Fälle:

  • Das Verhalten eines Objekts hängt von seinem Zustand ab, und es muss sein Verhalten zur Laufzeit und in Abhängigkeit von diesem Zustand ändern.
  • Die Operationen der Klasse besitzen große mehrteilige Bedingungsanweisungen, die vom Objektzustand abhängen. Dieser Zustand wird üblicherweise durch eine oder mehrere Aufzählungskonstanten repräsentiert. Oftmals enthalten mehrere Operationen dieselbe Struktur von Bedingungsanweisungen. Das Zustandsmuster verlgert jeden Zweig der Bedingungsanweidung in eine separate Klasse. Dies ermöglicht es Ihnen, den Objektzustand als ein eigenständiges Objekt zu behandeln, der unabhängig von anderen Objekten variiert werden kann.


Zuständigkeitskette (Chain of Responsiblility)

Zweck: Vermeide die Kopplung des Auslösers einer Anfrage mit seinem Empfänger, indem mehr als ein Objekt die Möglichkeit erhält, die Aufgabe zu erledigen. Verkette die empfangenden Objekte und leite die Anfrage an der Kette entlang, bis ein Objekt sie erledigt.
Struktur: Zuständigkeitskette
Abb. 3.11 Zuständigkeitskette
Teilnehmer:

  • Bearbeiter
    • definiert eine Schnittstelle zur Bearbeitung von Anfragen.
    • (optional) implementiert eine Verbindung zum Nachfolgeobjekt.-
  • KonkreterBearbeiter
    • arbeitet genau die Anfrage ab, für die er zuständig ist.
    • kann auf seinen Nachfolger zugreifen.
    • wenn der konkreteBearbeiter die Anfrage bearbeiten kann, tut er es auch; anderenfalls leitet er die Anfrage an das Nachfolgeobjekt weiter.
  • Klient
    • löst die Anfrage bei einem KonkreterBearbeiter-Objekt in der Kette aus.

Anwendbarkeit: Verwenden Sie eine Zustaändigkeitskette, wenn

  • mehr als ein Objekt eine Anfrage bearbeiten können soll und dasjenige Objekt, das dies tut, nicht von vornherein bekannt ist. Dieses Objekt muss dann zur Laufzeit automatisch bestimmt werden.
  • Sie eine Anfrage an eines von mehreren Objekten richten wollen, ohne den Empfänger explizit anzugeben.
  • die Menge der Objekte, welche eine Anfrage bearbeiten sollen, dynamisch festgelegt werden soll.

Summarized by: Dipl.-Ing. (univ.) Dipl.-Ing. (FH) Ralf Isken
Only for private use.
Source: Entwurfsmuster; Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides; Addison-Wesley; 1996


Literaturhinweise

1 James O. Coplien. Advanced C++ Programming Styles and Idioms. Addison-Wesley, Reading, MA, 1992 (zurück)
2 William F. Opdyke und Ralph E. Johnson. Vreating abstract sperclasses by refactoring.In Proceedings of the 21st Annual Computer Science Conference (ACM CSC '93), Seite 66-73, Inianapolis, IN, Februar 1993 (zurück)
3 Daniel C. Halbert und Patrick D. O'Brien. Object-orientated development. IEEE Software, 4(5):71-79, September 1987. (zurück)