Visitor模式,顾名思义,就是有客人要来拜访,当然客人不一定是谁,我们家也不一定就我一个人。所以是一个N:M的一个关系。
但是我们家里的人一般都是比较固定的。就我跟我老婆,孩子,偶尔爸妈过来住一住。而来访者,可能是随便谁谁。他来我们家拜访,我肯定是要接待的。
一般至少得开个门吧,然后我们还会开放一些空间给她参观,比如客厅,每个人都是可以参观的。而对于每个家庭成员,visitor可能要有不同的方式打交道,不同的visitor跟我们家每个成员打交道方式可能都不太一样。比如我叔叔辈的可能跟我爸妈聊天会更多。如果是我同学,肯定就跟我聊得更多。
好了,到现在为止,出现了两个角色。Visitor和我们家成员。当然我们家成员可以共享一个客厅,但是每个人都有一些私人物品。这个就不继续扩展了。
一般我们家成员组成了一个家庭(Composit)。
抽象一下,访问者我们叫Visitor,家庭成员叫Element。家庭就是一个Composit。对应着访问者模式类图看看,应该都能对应上了吧?
简单写了个demo:
#include "Element.h"
class ElementA;
class ElementB;
class Element;
class Visitor{
public:
Visitor(){}
~Visitor(){}
virtual void Visit(ElementA * ea);
virtual void Visit(ElementB * eb);
virtual void Visit(Element * e);
};
#include "Visitor.h"
void Visitor::Visit(ElementA * ea){
cout<<"visit ElementA:"<<ea->GetName()<<":"<<ea->GetValue()<<endl;
ea->SetValue(200);
cout<<"after visit ElementA:"<<ea->GetName()<<":"<<ea->GetValue()<<endl;
}
void Visitor::Visit(ElementB * eb){
cout<<"visit ElementB:"<<eb->GetName()<<":"<<eb->GetValue()<<endl;
eb->SetValue(100);
cout<<"after Visit ElementB:"<<eb->GetName()<<":"<<eb->GetValue()<<endl;
}
void Visitor::Visit(Element * e){
cout<<"Visit Element Father:"<<e->GetName()<<":"<<e->GetValue()<<endl;
e->SetValue(10);
cout<<"after visit Element:"<<e->GetName()<<":"<<e->GetValue()<<endl;
}
#include <iostream>
#include "Visitor.h"
using namespace std;
class Visitor;
class Element{
public:
Element(){}
~Element(){}
virtual void Accept(Visitor * visitor);
string & GetName(){
return name;
}
void SetName(string n){
name = n;
}
int & GetValue(){
return value;
}
void SetValue(int i){
value = i;
}
protected:
string name;
int value;
};
class ElementA :public Element{
public:
ElementA(){
name = "ElementA";
value = 10;
}
virtual void Accept(Visitor * visitor);
};
class ElementB : public Element{
public:
ElementB(){
name = "ElementB";
value = 20;
}
~ElementB(){}
virtual void Accept(Visitor * visitor);
};
#include "Element.h"
void Element::Accept(Visitor * visitor){
cout<<"do some job in Element Father"<<endl;
visitor->Visit(this);
}
void ElementA::Accept(Visitor * visitor){
cout<<"do some job in ElementA"<<endl;
visitor->Visit(this);
}
void ElementB::Accept(Visitor * visitor){
cout<<"do some job in ElementB"<<endl;
visitor->Visit(this);
}
#include <iostream>
#include <list>
#include "Visitor.h"
#include "Element.h"
using namespace std;
int main(){
//就不搞composit了,直接放到main里测试
list<Element *> elem_list;
ElementA *ea1 = new ElementA();
elem_list.push_back(ea1);
ElementA *ea2 = new ElementA();
elem_list.push_back(ea2);
ElementB *eb1 = new ElementB();
elem_list.push_back(eb1);
Visitor * v = new Visitor();
list<Element *>::iterator iter = elem_list.begin();
for (; iter != elem_list.end(); iter++){
(*iter)->Accept(v);
}
return 0;
}
该模式中假设Element是比较稳定的,而Visitor是经常变的部分。如果Element变化比较频繁,那么Visitor修改成本会比较大。
可以在Visitor父类中增加一些默认操作。Element父类也有一些默认的Accept动作。
Visitor访问对象一般都是一个相似的集合/组合,但是对此没有严格要求。Element完全可以不同(不同父类),只需要Element有Accept方法,Visitor中增加对应的处理函数即可。这使得Visitor使用比较灵活。