访问者模式(Visitor)
表示作用于某个对象结构中各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
代码举例
c++
#include <iostream>
#include <string>
#include <list>
#include <memory>
using namespace std;
class Action;
// 人的抽象类(Element)
class Person
{
public:
virtual void Accept(shared_ptr<Action> visitor) = 0;
};
// 注意forward declaration怎么写
class Man;
class Woman;
// 状态的抽象类(Visitor)
class Action
{
public:
virtual void GetManConclusion(const Man& concreteElementA) = 0;
virtual void GetWomanConclusion(const Woman& concreteElementA) = 0;
};
// 具体状态类
class Success : public Action
{
public:
void GetManConclusion(const Man& concreteElementA) override
{
cout << "男人成功" << "时, 背后多半有一个伟大的女人。" << endl;
}
void GetWomanConclusion(const Woman& concreteElementB) override
{
cout << "女人成功" << "时, 背后大多有一个不成功的男人。" << endl;
}
};
class Failing : public Action
{
public:
void GetManConclusion(const Man& concreteElementA) override
{
cout << "男人失败" << "时, 蒙头喝酒,谁也不劝。" << endl;
}
void GetWomanConclusion(const Woman& concreteElementB) override
{
cout << "女人失败" << "时, 眼泪汪汪,谁也劝不了。" << endl;
}
};
class Amativeness : public Action
{
public:
void GetManConclusion(const Man& concreteElementA) override
{
cout << "男人恋爱" << "时, 凡事不懂也要装懂。" << endl;
}
void GetWomanConclusion(const Woman& concreteElementB) override
{
cout << "女人恋爱" << "时, 遇事懂也装不懂。" << endl;
}
};
// 具体的Person, ConcreteElement
class Man : public Person
{
public:
void Accept(shared_ptr<Action> visitor) override
{
visitor->GetManConclusion(*this);
}
};
class Woman : public Person
{
public:
void Accept(shared_ptr<Action> visitor) override
{
visitor->GetWomanConclusion(*this);
}
};
// ObjectStructure类,提供一个高层的接口以允许枚举访问所有元素
class ObjectStructure
{
public:
// 增加
void Attach(shared_ptr<Person> element)
{
elements_.push_back(element);
}
// 移除
void Detach(shared_ptr<Person> element)
{
elements_.remove(element);
}
// 打印
void Display(shared_ptr<Action> visitor)
{
for (auto& e : elements_)
{
e->Accept(visitor);
}
}
private:
list<shared_ptr<Person>> elements_;
};
// 客户端代码
void Client()
{
ObjectStructure o;
o.Attach(make_shared<Man>());
o.Attach(make_shared<Woman>());
// 成功的反应
auto v1 = make_shared<Success>();
o.Display(v1);
// 失败的反应
auto v2 = make_shared<Failing>();
o.Display(v2);
// 恋爱的反应
auto v3 = make_shared<Amativeness>();
o.Display(v3);
}
int main()
{
Client();
return 0;
}
输出为
男人成功时, 背后多半有一个伟大的女人。
女人成功时, 背后大多有一个不成功的男人。
男人失败时, 蒙头喝酒,谁也不劝。
女人失败时, 眼泪汪汪,谁也劝不了。
男人恋爱时, 凡事不懂也要装懂。
女人恋爱时, 遇事懂也装不懂。
由于使用了双分派,当我们需要添加一个新的状态的时候,只需要增加一个状态的子类,而不需要改动其他类的代码。
适用条件
* 访问者模式适用于数据结构相对稳定的系统。例如上面的人分为男人和女人
* 访问者模式将数据结构和作用于结构上的操作之间的耦合分开,使得操作可以相对自由的演化。
* 增加新的操作实际上就是增加了数据结构的一个访问者。
* 相应的,这个模式的缺点就是不方便增加新的数据结构。