Ich bin nicht sehr vertraut mit dem Besuchermuster. Mal sehen, ob ich es richtig verstanden habe. Angenommen, Sie haben eine Hierarchie von Tieren
class Animal { };
class Dog: public Animal { };
class Cat: public Animal { };
(Nehmen wir an, es handelt sich um eine komplexe Hierarchie mit einer gut etablierten Schnittstelle).
Jetzt wollen wir eine neue Operation in die Hierarchie einfügen, nämlich dass jedes Tier seinen Ton macht. Solange die Hierarchie so einfach ist, kann man das mit einfachem Polymorphismus machen:
class Animal
{ public: virtual void makeSound() = 0; };
class Dog : public Animal
{ public: void makeSound(); };
void Dog::makeSound()
{ std::cout << "woof!\n"; }
class Cat : public Animal
{ public: void makeSound(); };
void Cat::makeSound()
{ std::cout << "meow!\n"; }
Wenn Sie jedoch so vorgehen, müssen Sie jedes Mal, wenn Sie eine Operation hinzufügen wollen, die Schnittstelle zu jeder einzelnen Klasse der Hierarchie ändern. Nehmen Sie stattdessen an, dass Sie mit der ursprünglichen Schnittstelle zufrieden sind und sie so wenig wie möglich ändern wollen.
Das Visitor-Muster ermöglicht es Ihnen, jede neue Operation in eine geeignete Klasse zu verschieben, und Sie müssen die Schnittstelle der Hierarchie nur einmal erweitern. Gehen wir es an. Zunächst definieren wir eine abstrakte Operation (die Klasse "Visitor" in GoF ), die für jede Klasse in der Hierarchie eine Methode hat:
class Operation
{
public:
virtual void hereIsADog(Dog *d) = 0;
virtual void hereIsACat(Cat *c) = 0;
};
Dann ändern wir die Hierarchie, um neue Operationen zu akzeptieren:
class Animal
{ public: virtual void letsDo(Operation *v) = 0; };
class Dog : public Animal
{ public: void letsDo(Operation *v); };
void Dog::letsDo(Operation *v)
{ v->hereIsADog(this); }
class Cat : public Animal
{ public: void letsDo(Operation *v); };
void Cat::letsDo(Operation *v)
{ v->hereIsACat(this); }
Schließlich wird die eigentliche Operation durchgeführt, ohne weder Katze noch Hund zu ändern :
class Sound : public Operation
{
public:
void hereIsADog(Dog *d);
void hereIsACat(Cat *c);
};
void Sound::hereIsADog(Dog *d)
{ std::cout << "woof!\n"; }
void Sound::hereIsACat(Cat *c)
{ std::cout << "meow!\n"; }
Jetzt haben Sie die Möglichkeit, Operationen hinzuzufügen, ohne die Hierarchie weiter zu verändern. So funktioniert es:
int main()
{
Cat c;
Sound theSound;
c.letsDo(&theSound);
}