21. Januar 2013

Entwurfsmuster: Besucher

In diesem Post, der sich wie die vorherigen auch, in die Serie über Software-Entwurfsmuster eingliedert, soll ein Abriss über das Verhaltensmuster "Besucher" (engl. Visitor-Pattern) gegeben werden. Dessen Verwendung zielt auf Objektstrukturen ab, auf deren Elemente verschiedene, nicht miteinander verwandte Operationen ausgeführt werden sollen. Die Definition der Klassen, die als Elemente der Objektstruktur instanziiert werden gestaltet sich oft schwierig, da sie unter einer gemeinsamen Schnittstelle zusammenzufassen sind, was im Widerspruch zu der Anforderung steht, verschiedene Operationen anzubieten.

Der Lösungsansatz, den das Besucher-Pattern vorsieht, ist die Auslagerung der Operationen in externe Besucherklassen. Die zu besuchenden Klassen wiederrum implementieren eine Schnittstelle, die zum Empfang eines solchen Besuchers dient. Das folgende Klassendiagramm zeigt das Zusammenspiel der daraus resultierenden Klassen und Interfaces.

Die Klassen und Interfaces des Besucher-Patterns als Klassendiagramm (Klicken zum Vergrößern)

Das Interface "Visitor" definiert die Schnittstelle, die von allen Besuchern implementiert werden muss. Dies beinhaltet je eine visit(..)-Methode für jeden vorhandenen Elementtyp der Struktur. Die einzelnen Element-Klassen implementieren wiederrum das Interface "VisitableElement", das eine Methode vorschreibt, über die beliebige Besucher, wie in dem Code-Fragment angedeutet, entgegen genommen werden können, um auf den Daten des Elements zu operieren.

Vorteile:
  • Neue Operationen lassen sich sehr leicht über die Implementierung neuer Besucherklassen hinzufügen, ohne dass die zu besuchenden Klassen angepasst werden müssen.
  • Die Operationen werden zentral verwaltet und von besucherfremden Operationen getrennt.
  • Besucher können wiederverwendet werden und auf verschiedene Objektstrukturen angewendet werden.
  • Die Elementklassen bleiben übersichtlich.
Nachteile:
  • Da die Besucher alle möglichen Elementtypen der Struktur kennen muss um jeweils eine passende Methode anbieten zu können, müssen bei der Einführung eines neuen Strukturelements alle bestehenden Besucherklassen um eine entsprechende Methode erweitert werden.
  • Das Kapselungsprinzip wird verletzt, da die Elemente der Objektstruktur all ihre Attribute über öffentliche Methoden den Besuchern zugänglich machen müssen.
Bei der Umsetzung des Besucher-Patterns ist es wichtig, darüber Klarheit zu schaffen, wer für die Traversierung über die Objektstruktur verantwortlich sein soll. Dies kann einerseits die Struktur selbst sein, die einem an sie übergebenen Visitor nacheinander alle Elemente vorlegt, was jedoch zur Folge hat, dass immer über die gesamte Struktur traversiert werden muss. Diese Einschränkung kann umgangen werden, indem die Traversierung in jedem Besucher implementiert wird, was aber wiederrum den Nachteil hat, dass in jedem Besucher zusätzlich der dafür notwendige Code anfällt, insofern dies nicht in einer abstrakten Basisklasse erledigt werden kann. Die dritte Möglichkeit besteht darin, die Traversierung komplett getrennt zu behandeln, indem etwa ein Iterator benutzt wird.

Besucher können beim Besuchen der Elemente Informationen sammeln und für die weitere Verarbeitung speichern. Diese Information muss dann nicht als Argument durch alle Operationen durchgereicht werden oder in globalen Variablen gehalten werden.

Über die Definition einer abstrakten Visitor-Basisklasse können Leerimplementierungen der visit-Methoden eingeführt werden, die erst später bei Bedarf in den konkreten Besuchern implementiert werden.

Keine Kommentare:

Kommentar veröffentlichen