ブログでビジターパターンについて言及されているのをよく見かけますが、正直言って私には理解できません。パターンに関するWikipediaの記事その仕組みは理解していますが、いつ使用すればよいのかまだわかりません。
最近デコレータ パターンを理解し、あらゆる場所でその使用法を目にするようになった私としては、この一見便利なパターンも直感的に理解できるようになりたいです。
ベストアンサー1
私はビジターパターンにあまり詳しくありません。正しく理解できたかどうか確認してみましょう。動物の階層があるとします
class Animal { };
class Dog: public Animal { };
class Cat: public Animal { };
(インターフェースが確立された複雑な階層であると仮定します。)
ここで、階層に新しい操作を追加して、各動物に音を鳴らしてもらいます。階層がこのように単純な場合は、単純なポリモーフィズムで実行できます。
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"; }
しかし、この方法で進めると、操作を追加するたびに、階層のすべてのクラスへのインターフェイスを変更する必要があります。ここで、元のインターフェイスに満足しており、それに対する変更をできるだけ少なくしたいとします。
ビジターパターンでは、新しい操作を適切なクラスに移動することができ、階層のインターフェースを一度だけ拡張するだけで済みます。やってみましょう。まず、抽象操作(「Visitor」クラス)を定義します。ゴーフ) には、階層内のすべてのクラスに対応するメソッドがあります。
class Operation
{
public:
virtual void hereIsADog(Dog *d) = 0;
virtual void hereIsACat(Cat *c) = 0;
};
次に、新しい操作を受け入れるために階層を変更します。
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); }
最後に、 Cat も Dog も変更せずに実際の操作を実装します。
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"; }
これで、階層を変更せずに操作を追加できるようになりました。仕組みは次のとおりです。
int main()
{
Cat c;
Sound theSound;
c.letsDo(&theSound);
}