Die ob­jekt­ori­en­tier­te Pro­gram­mie­rung (OOP), die als Unterform des im­pe­ra­ti­ven Pro­gram­mier­pa­ra­dig­mas ein­ge­stuft wird, hat in den ver­gan­ge­nen Jahren stark an Bedeutung gewonnen. Die Option, alle Bausteine eines Software-Projekts als Objekt zu be­schrei­ben, dessen Verhalten sich durch die ent­spre­chen­den Klassen bestimmen lässt, bietet einige ent­schei­den­de Vorzüge gegenüber anderen Pro­gram­mier­sti­len. Ins­be­son­de­re die Mög­lich­keit, ent­wor­fe­ne Pro­gramm­tei­le pro­blem­los wie­der­zu­ver­wen­den, ist für viele Ent­wick­ler ein klares Argument für die Ver­wen­dung der OOP.

Um diese Wie­der­ver­wend­bar­keit sowie die Im­ple­men­tie­rung, An­pass­bar­keit und Test­fä­hig­keit der ein­ge­bau­ten Objekte noch einfacher zu gestalten, wurden in dem Buch „Design Patterns: Elements of Reusable Object-Oriented Software“ die GoF-Ent­wurfs­mus­ter vor­ge­stellt. Eines dieser über 20 ver­schie­de­nen Design Patterns ist das so­ge­nann­te Visitor Pattern bzw. Visitor Design Pattern (zu Deutsch: Besucher-Ent­wurfs­mus­ter), das in den nach­fol­gen­den Ab­schnit­ten aus­führ­lich vor­ge­stellt werden soll.

Was ist das Visitor Pattern?

Das Visitor Design Pattern, kurz Visitor Pattern, stellt eine Mus­ter­lö­sung dafür dar, einen Al­go­rith­mus von der Ob­jekt­struk­tur zu trennen, auf der er arbeitet. Es be­schreibt einen Weg, um neue Ope­ra­tio­nen zu be­stehen­den Ob­jekt­struk­tu­ren hin­zu­fü­gen, ohne dass diese Struk­tu­ren hierfür mo­di­fi­ziert werden müssen. Dank dieser Ei­gen­schaft stellt das Visitor Pattern eine mögliche Option für die Umsetzung des Open-Closed-Prinzips (OCP) dar. Dieses Prinzip der ob­jekt­ori­en­tier­ten Software-Ent­wick­lung beruht darauf, dass jegliche Software-Einheiten – wie Module, Klassen oder Methoden – gleich­zei­tig offen (open) für Er­wei­te­run­gen und ver­schlos­sen (closed) für Mo­di­fi­ka­tio­nen sind.

Hinweis

Im Deutschen be­zeich­net man das Visitor Pattern auch als Besucher-Ent­wurfs­mus­ter bzw. Besucher-Muster.

Das Visitor Pattern ist eines von insgesamt 23 Ent­wurfs­mus­ter (Kategorie: Ver­hal­tens­mus­ter), die 1994 von den In­for­ma­ti­kern Erich Gamma, Richard Helm, Ralph Johnson und John Vlissides be­schrie­ben und ver­öf­fent­licht wurden. Da die Vier in der Ent­wick­ler­sze­ne auch als „Gang of Four“ (dt. Vie­rer­ban­de) – kurz GoF – bekannt sind, hat sich für die besagten Patterns der Name GoF-Ent­wurfs­mus­ter ein­ge­bür­gert.

Welchen Zweck erfüllt das Visitor Design Pattern?

Besteht die Ob­jekt­struk­tur aus vielen un­ver­bun­de­nen Klassen und es werden häufig neue Ope­ra­tio­nen benötigt, ist es für Ent­wick­ler höchst un­kom­for­ta­bel, für jede neue Operation eine neue Un­ter­klas­se zu im­ple­men­tie­ren. Das Resultat dieser Vor­ge­hens­wei­se: Ein System mit diversen ver­schie­de­nen Kno­ten­klas­sen, das nicht nur schwer zu verstehen, sondern auch schwer zu pflegen und zu mo­di­fi­zie­ren ist. Die ent­schei­den­de Instanz des Visitor Patterns, der Besucher (Visitor), erlaubt daher das Hin­zu­fü­gen neuer, vir­tu­el­ler Funk­tio­nen zu einer Familie von Klassen, ohne diese Klassen mo­di­fi­zie­ren zu müssen.

Hinweis

Virtuelle Funk­tio­nen bzw. Methoden de­fi­nie­ren aus­zu­füh­ren­de Ziel­funk­tio­nen, deren Ziel zur Kom­pi­lie­rungs­zeit noch nicht bekannt sein muss. Sie stellen ein wichtiges Werkzeug ob­jekt­ori­en­tier­ter Sprachen dar.

Das Besucher-Ent­wurfs­mus­ter sieht vor, dass ein solches Visitor-Objekt separat definiert wird – mit dem Plan, eine Operation zu im­ple­men­tie­ren, die auf einem Element bzw. mehreren Elementen der Ob­jekt­struk­tur aus­ge­führt wird. Clients, die auf die Ob­jekt­struk­tur zugreifen, rufen dann auf dem be­trof­fe­nen Element Methoden wie „accept(visitor)“ auf, die die Anfrage an das ak­zep­tier­te Visitor-Objekt de­le­gie­ren. In­fol­ge­des­sen kann das Besucher-Objekt die jeweilige Operation ausführen.

Grafische Dar­stel­lung des Visitor Patterns (UML-Diagramm)

Das Zu­sam­men­spiel zwischen den vor­han­de­nen Elementen und den ein­ge­bun­de­nen Visitor-Objekten nach dem Visitor Design Pattern lässt sich am besten anhand einer gra­fi­schen Dar­stel­lung der Be­zie­hun­gen und Vorgänge einer möglichen ob­jekt­ori­en­tier­ten Software ver­deut­li­chen. Optimal zu diesem Zweck geeignet ist die beliebte Mo­del­lie­rungs­spra­che UML (Unified Modeling Language), die aus diesem Grund auch im nach­fol­gen­den Klas­sen­dia­gramm für das Visitor Pattern verwendet wurde.

Die Vor- und Nachteile des Visitor Patterns

Das Visitor Pattern stellt einen bereits aus­ge­feil­ten, gut funk­tio­nie­ren­den Weg dar, um be­stehen­de Einheiten einer ob­jekt­ori­en­tier­ten Software zu erweitern. Soll eine neue Operation hin­zu­ge­fügt werden, gelingt dies pro­blem­los durch die De­fi­ni­ti­on eines neuen Besuchers. Nebenbei er­mög­licht diese Vor­ge­hens­wei­se auch, jeglichen funk­tio­nel­len Code zu zen­tra­li­sie­ren: Die jeweilige Im­ple­men­tie­rung einer Operation befindet sich zentral in der Visitor-Klasse und muss nicht extra in den einzelnen anderen Klassen ergänzt werden. Der ent­schei­den­de Vorteil einer Software nach Visitor Design Pattern besteht zu­sam­men­ge­fasst darin, dass der zu­grun­de­lie­gen­de Quellcode der ver­wen­de­ten Objekte nicht ständig an­zu­pas­sen ist. Die Logik wird statt­des­sen auf die als Stell­ver­tre­ter agie­ren­den Besucher und Besucher-Klassen auf­ge­teilt.

Natürlich ist aber auch das Besucher-Ent­wurfs­mus­ter nicht in allen Punkten perfekt. Wer nach den Grund­sät­zen dieses Musters arbeitet, muss sich folgender Sache bewusst sein: Bereits geringe Ver­än­de­run­gen an der Klasse eines Elements haben in den meisten Fällen zur Folge, dass auch zu­ge­wie­se­ne Visitor-Klassen an­zu­pas­sen sind. Zudem bleibt zu­sätz­li­che Arbeit bei der nach­träg­li­chen Ein­füh­rung neuer Elemente nicht erspart, denn auch für diese gilt es, visit()-Methoden zu im­ple­men­tie­ren, die wiederum in den Con­cre­te­Vi­si­tor-Klassen zu ergänzen sind. Die her­vor­ra­gen­de Er­wei­ter­bar­keit der Software-Einheiten ist also an ein gewisses Maß an Aufwand geknüpft.

Wo kommt das Visitor Pattern zum Einsatz?

Das Visitor Design Pattern kann wie­der­keh­ren­de Auf­ga­ben­stel­lun­gen in der Software-Ent­wick­lung erheblich ver­ein­fa­chen. Ins­be­son­de­re für Ent­wick­ler, die dem ob­jekt­ori­en­tier­ten Pro­gram­mier­pa­ra­dig­ma folgen, lohnt sich eine Aus­ein­an­der­set­zung mit dem Ent­wurfs­mus­ter. Seit seiner Vor­stel­lung im Jahr 1994 hat sich das Muster folglich in der Pro­gram­mier­sze­ne zu einer festen Größe ent­wi­ckelt, wobei der Typ des Software-Projekts im Prinzip keine ent­schei­den­de Rolle für den Nutz­fak­tor des Patterns spielt. Auch hin­sicht­lich der pro­fi­tie­ren­den Pro­gram­mier­spra­chen bestehen grund­sätz­lich keine konkreten Ein­schrän­kun­gen für das Mus­ter­prin­zip, mit Ausnahme der Tatsache, dass es ins­be­son­de­re auf das ob­jekt­ori­en­tier­te Paradigma zu­ge­schnit­ten ist.

Beliebte Sprachen, in denen das Visitor Pattern eine ele­men­ta­re Rolle spielt, sind unter anderem folgende:

  • C++
  • C#
  • Java
  • PHP
  • Python
  • Ja­va­Script
  • Golang
iueor-qViR4.jpg Zur Anzeige dieses Videos sind Cookies von Drittanbietern erforderlich. Ihre Cookie-Einstellungen können Sie hier aufrufen und ändern.

Pra­xis­na­hes Beispiel für den Einsatz des Visitor Patterns

Den Nutzen und Zweck des Visitor Patterns zu verstehen, ist von außen be­trach­tet gar nicht so einfach. Wer heute pro­gram­mie­ren lernt, kommt al­ler­dings au­to­ma­tisch mit dem Muster und dessen Umsetzung in Berührung.

Als leichter greifbare Analogie aus dem realen Leben wird für das Besucher-Ent­wurfs­mus­ter häufig die Fahrt mit einem Taxi auf­ge­führt: Ein Kunde bestellt ein Taxi, das auf Wunsch bis an seine Haustür kommt. Sitzt die Person erst einmal in dem „be­su­chen­den“ Taxi, ist dieses (bzw. der Fahrer) gänzlich in Kontrolle über den Transport der Person.

Auch das Einkaufen in einem Su­per­markt wird häufig als Bild für die Funk­ti­ons­wei­se des Visitor Patterns verwendet: Die ein­kau­fen­de Person sammelt im Ein­kaufs­wa­gen die ge­wünsch­te Ware, die bildlich für das Set an Elementen der Ob­jekt­struk­tur steht. An der Kasse an­ge­kom­men fungiert das kas­sie­ren­de Personal als Visitor, der die Preise und das Gewicht der einzelnen Shopping-Güter (bzw. Elemente) scannt, um die an­fal­len­den Ge­samt­kos­ten zu errechnen.

Beispiel-Code nach Visitor-Pattern-Ansatz (PHP)

Ab­schlie­ßend prä­sen­tiert der nach­fol­gen­de Code eine einfache, grund­le­gen­de Umsetzung des Visitor Patterns in PHP.

return 'B';
    }
    public function getData() {
        return $this->the_data;
    }
    public function entgegennehmen(Besucher $besucher) {
        $besucher->BesuchVonElementB($this);
    }
}
abstract class Besucher {
    abstract function BesuchVonElementA(ElementA $elem);
    abstract function BesuchVonElementB(ElementB $elem);
}
class Besucher1 extends Besucher {
    private $characteristics;
    public function getCharacs() {
        return $this->characteristics;
    }
    public function BesuchVonElementA(ElementA $elem) {
        $this->characteristics = 'Info:'.$elem->getInfo();
    }
    public function BesuchVonElementB(ElementB $elem) {
        $this->characteristics = 'DATA:'.$elem->getData().'!!';
    }
}
function Test() {
    write_line('Testanfang');
    // Objektstruktur
    $elemente = array (
        new ElementA('Hallo', 'Neu!!'),
        new ElementB('Endlich.'),
    );
    $bes1 = new Besucher1();
    foreach ($elemente as $element) {
        $element->entgegennehmen($bes1);
        write_line('Nach Besuch von Element '.$element->getName().': '.$bes1-            >getCharacs());
}
}
function write_line($text) {
    print $text.'<br/>';
}
Test();

Die Ausgabe dieses Beispiel-Code-Snippets sieht dann wie folgt aus:

Testanfang
Nach Besuch von Element A: Info:[Hallo--Neu!!]
Nach Besuch von Element B: DATA:(Endlich.)!!
Zum Hauptmenü