访问者模式的目的是封装一些施加于某种数据结构之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。访问者模式适应于那种数据结构相对稳定的系统,它把数据结构和作用于数据机构之上的操作的耦合完全解开,使得操作集合可以自由的演化。
访问者模式增加一个新的操作也很简单,只要增加一个新的访问者类即可。
优点: 1、符合单一职责原则。 2、优秀的扩展性。 3、灵活性。
缺点: 1、具体元素对访问者公布细节,违反了迪米特原则。 2、具体元素变更比较困难。 3、违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
类图如下:
示例代码如下:
#include <iostream>
#include <string>
#include <list>
using namespace std;
class ParkElement;
/* 抽象访问者基类 */
class visitor
{
public:
virtual void visit(ParkElement* p) = 0;
};
/* 抽象被访问者基类 */
class ParkElement
{
public:
virtual void accept(visitor* v) = 0;
string name;
};
/* 具体公园子类 */
class ParkA :public ParkElement
{
public:
ParkA(string name)
{
this->name = name;
}
/* 接受访问者访问,不同的访问者可以有不同的操作 */
virtual void accept(visitor* v)
{
v->visit(this);
}
};
/* 具体公园子类 */
class ParkB :public ParkElement
{
public:
ParkB(string name)
{
this->name = name;
}
/* 接受访问者访问,不同的访问者可以有不同的操作 */
virtual void accept(visitor* v)
{
v->visit(this);
}
};
/* 使用元素集合代表整个公园 */
class Park :public ParkElement
{
public:
Park()
{
m_list.clear();
}
/* 添加元素 */
void addParkElement(ParkElement* p)
{
m_list.push_back(p);
}
/* 接受访问者访问,访问公园内所有元素 */
virtual void accept(visitor* v)
{
for (list<ParkElement*>::iterator it = m_list.begin();it != m_list.end();it++)
{
(*it)->accept(v);
}
}
private:
list<ParkElement*> m_list;
};
/* 具体访问者子类 */
class VisitorA:public visitor
{
public:
/* 该访问者是负责打扫公园的 */
virtual void visit(ParkElement* p)
{
cout<<"清洁工A完成了公园的 "<<p->name<<" 部分的打扫"<<endl;
}
};
/* 具体访问者子类 */
class VisitorB :public visitor
{
public:
/* 该访问者是负责打扫公园的 */
virtual void visit(ParkElement* p)
{
cout << "清洁工B完成了公园的 " << p->name << " 部分的打扫" << endl;
}
};
class ManagerVisitor :public visitor
{
public:
/* 该访问者是负责视察公园的 */
virtual void visit(ParkElement* p)
{
cout << "管理者视察了公园的" <<p->name <<endl;
}
};
int main()
{
VisitorA* Va = new VisitorA;
VisitorB* Vb = new VisitorB;
ParkA* Pa = new ParkA("花园");
ParkB* Pb = new ParkB("小溪边");
Pa->accept(Va);
Pb->accept(Vb);
ManagerVisitor* Mv = new ManagerVisitor;
Park* p = new Park;
p->addParkElement(Pa);
p->addParkElement(Pb);
p->accept(Mv);
delete Va;
delete Vb;
delete Pa;
delete Pb;
delete Mv;
delete p;
system("pause");
return 0;
}
运行结果如下: