访问者模式的目的是封装一些施加于某种数据结构之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。访问者模式适应于那种数据结构相对稳定的系统,它把数据结构和作用于数据机构之上的操作的耦合完全解开,使得操作集合可以自由的演化。

访问者模式增加一个新的操作也很简单,只要增加一个新的访问者类即可。

优点: 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;
}

运行结果如下: