访问者模式的目的是封装一些施加于某种数据结构之上的操作,一旦这些操作需要修改的话,接受这个操作的数据结构可以保持不变。访问者模式适应于那种数据结构相对稳定的系统,它把数据结构和作用于数据机构之上的操作的耦合完全解开,使得操作集合可以自由的演化。
访问者模式增加一个新的操作也很简单,只要增加一个新的访问者类即可。
优点: 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; }
运行结果如下: