When should I use the Visitor Design Pattern?

I keep seeing references to the visitor pattern in blogs but I’ve got to admit, I just don’t get it. I read the wikipedia article for the pattern and I understand its mechanics but I’m still confused as to(至于,关于;就……而论) when I’d use it.As someone who just recently really got the decorator pattern and is now seeing uses for it absolutely everywhere I’d like to be able to really understand intuitively(adv. 直观地;直觉地) this seemingly handy pattern as well.
I’m not very familiar with the Visitor pattern. Let’s see if I got it right. Suppose you have a hierarchy of animals

class Animal {  };
class Dog: public Animal {  };
class Cat: public Animal {  };

(Suppose it is a complex hierarchy with a well-established interface.)
Now we want to add a new operation to the hierarchy, namely we want each animal to make its sound. As far as the hierarchy is this simple, you can do it with straight polymorphism:

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"; }

But proceeding in this way, each time you want to add an operation you must modify the interface to every single class of the hierarchy. Now, suppose instead that you are satisfied with the original interface, and that you want to make the fewest possible modifications to it.
The Visitor pattern allows you to move each new operation in a suitable class, and you need to extend the hierarchy’s interface only once. Let’s do it. First, we define an abstract operation (the “Visitor” class in GoF) which has a method for every class in the hierarchy:

class Operation
{
public:
    virtual void hereIsADog(Dog *d) = 0;
    virtual void hereIsACat(Cat *c) = 0;
};

Then, we modify the hierarchy in order to accept new operations:

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); }

Finally, we implement the actual operation, without modifying neither Cat nor 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"; }

Now you have a way to add operations without modifying the hierarchy anymore. Here is how it works:

int main()
{
    Cat c;
    Sound theSound;
    c.letsDo(&theSound);
}

The reason for your confusion is probably that the Visitor is a fatal misnomer. Many (prominent1!) programmers have stumbled over this problem. What it actually does is implement double dispatching in languages that don’t support it natively (most of them don’t).

1) My favourite example is Scott Meyers, acclaimed author of “Effective C++”, who called this one of his most important C++ aha! moments ever.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值