访问者模式

一个处方单(Accepter),可能被不同的人(Visitor)拿去做不同的事,有的拿去划价,有的拿去拿药.

一个员工列表(Accepter),人力资源(Visitor)要统计考勤,财务部(Visitor)要结算工资…

所以访问者的场景还的真的挺多的.

2018-08-11-17-26-13

被访问者或者叫元素类提供一个方法 accept,接受所谓的访问者 visit,实际又是调用visit->visit(this).即把自己的信息给访问者,访问者再调用自己的某些方法。

这个某些方法是封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,才需要改变访问者来改变操作.

对 Element 来说,就是主人. 如果需要增加新的操作,就增加新的 Visitor,间接实现对 Element 的操作

核心就是来自 Element 的 accept 方法,间接把自己通过 this 给了 visitor,visitor 在 visit 方法里可以实现新的操作.

Element 对与 Visitor 是可控的,也就是只有 accept 的,才可以,其余的不可以.

void accept(Visitor* v) {
        v->visit(this); //执行访问者的动作,一般是this传入,也就是访问者来访时,是携带了自己的信息的
    }

比如:数据结构(Element)与数据操作(Visitor)的分离. 跟 stl 的思路还不太像的.

具体例子:

#include <iostream>

using namespace std;
//定义两种访问者,分别访问不同的元素

class Element;
class Visitor {
	public:
		//定义可能要访问哪些元素
		virtual void visit(Element * v) = 0;
		virtual ~Visitor(){}
};
class Element {
	public:
		virtual ~Element(){}
		//定义可能有哪些访问者来访
		virtual void accept(Visitor* v) {
			v->visit(this);}
		virtual void jobA() = 0;
		virtual void jobB() = 0;
		virtual void jobC() = 0;
		//这是模板模式,叫框架模式更好
		void job_process1() { jobA();jobB();jobC();}
		void job_process2() { jobC();jobB();jobA();}
};



/** @brief ElementA
 * 某个元素的具体类,
 * 有3个工作,但是不想直接调用.通过访问者来间接使用,这样改变访问者,也改变了功能
 * */
class ElementA :public Element {

	void jobA() {cout << __func__ << endl;}
	void jobB() {cout << __func__ << endl;}
	void jobC() {cout << __func__ << endl;}
};

class ElementB :public Element {

	void jobA() {cout << __func__ << "for ElementB\n" << endl;}
	void jobB() {cout << __func__ << "for ElementB\n" << endl;}
	void jobC() {cout << __func__ << "for ElementB\n" << endl;}
};


class VisitorA :public Visitor{
	void visit(Element* e) {
		e->job_process1();
	}
};

class VisitorB :public Visitor{
	void visit(Element* e) {
		e->job_process2();
	}
};

int main(int argc , char* argv[])
{
	Element* ea = new ElementA();
	Element* eb = new ElementB();
	Visitor* va = new VisitorA();
	Visitor* vb = new VisitorB();
	ea->accept(va); //实际调用了继承的job_process1,用访问者做了一层封装
	ea->accept(vb);

	eb->accept(va);
	eb->accept(vb);
	return 0;
}

结果:

jobA
jobB
jobC
jobC
jobB
jobA
jobAfor ElementB

jobBfor ElementB

jobCfor ElementB

jobCfor ElementB

jobBfor ElementB

jobAfor ElementB