Visitor模式:
Visitor模式表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。Visitor模式将有关的行为集中到一个访问者对象中,即将更新(变更)封装到一个类中(访问操作),并由待更改类提供一个接收接口。
Visitor模式的目的是要把处理从数据结构分离出来。很多系统更可以按照算法和数据结构分开,如果这样的系统由比较稳定的数据结构,又有易于变化的算法的话,使用Visitor模式是比较合适的,因为Visitor模式使得算法操作的增加变得容易。反之,如果这样的系统的数据结构对象易于变化,经常要有新的数据对象增加进来,就不适合使用访问者模式。
Visitor模式典型的结构图为:
参考《大话设计模式》中关于Visitor模式的讲解,以男人和女人对于相同事物的态度的不同反应为例。将《设计模式精解-GoF 23种设计模式解析》的例子稍作修改,以方便理解,其实现代码如下:
//Visitor.h
#ifndef _VISITOR_H_
#define _VISITOR_H_
class ConcreteElementA;
class ConcreteElementB;
class Element_Person;
// 对事物的反应
class Visitor_Action
{
public:
virtual ~Visitor_Action();
virtual void
VisitConcreteElementA(Element_Person* elm) = 0;
virtual void
VisitConcreteElementB(Element_Person* elm) = 0;
protected:
Visitor_Action();
private:
};
// 对失恋的态度
class ConcreteVisitorA_Lovesick : public Visitor_Action
{
public:
ConcreteVisitorA_Lovesick();
virtual ~ConcreteVisitorA_Lovesick();
virtual void
VisitConcreteElementA(Element_Person* elm);
virtual void
VisitConcreteElementB(Element_Person* elm);
protected:
private:
};
// 对结婚的态度
class ConcreteVisitorB_Marriage : public Visitor_Action
{
public:
ConcreteVisitorB_Marriage();
virtual ~ConcreteVisitorB_Marriage();
virtual void
VisitConcreteElementA(Element_Person* elm);
virtual void
VisitConcreteElementB(Element_Person* elm);
protected:
private:
};
#endif //~_VISITOR_H_
//Visitor.cpp
#include "Visitor.h"
#include "Element.h"
#include <iostream>
using namespace std;
Visitor_Action::Visitor_Action()
{
}
Visitor_Action::~Visitor_Action()
{
}
ConcreteVisitorA_Lovesick::ConcreteVisitorA_Lovesick()
{
}
ConcreteVisitorA_Lovesick::~ConcreteVisitorA_Lovesick()
{
}
void ConcreteVisitorA_Lovesick::VisitConcreteElementA(Element_Person* elm)
{
cout<<"i will visit ConcreteElementA...男人失恋了,喝酒"<<endl;
}
void ConcreteVisitorA_Lovesick::VisitConcreteElementB(Element_Person* elm)
{
cout<<"i will visit ConcreteElementB...女人失恋了,哭"<<endl;
}
ConcreteVisitorB_Marriage::ConcreteVisitorB_Marriage()
{
}
ConcreteVisitorB_Marriage::~ConcreteVisitorB_Marriage()
{
}
void ConcreteVisitorB_Marriage::VisitConcreteElementA(Element_Person* elm)
{
cout<<"i will visit ConcreteElementA...男人结婚了,交钱给老婆管"<<endl;
}
void ConcreteVisitorB_Marriage::VisitConcreteElementB(Element_Person* elm)
{
cout<<"i will visit ConcreteElementB...女人结婚了,管男人的钱"<<endl;
}
//Element.h
#ifndef _ELEMENT_H_
#define _ELEMENT_H_
class Visitor_Action;
// 人
class Element_Person
{
public:
virtual ~Element_Person();
virtual void Accept(Visitor_Action* vis) = 0;
protected:
Element_Person();
private:
};
// 女人
class ConcreteElementA_Women : public Element_Person
{
public:
ConcreteElementA_Women();
~ConcreteElementA_Women();
void Accept(Visitor_Action* vis);
protected:
private:
};
// 男人
class ConcreteElementB_Men : public Element_Person
{
public:
ConcreteElementB_Men();
~ConcreteElementB_Men();
void Accept(Visitor_Action* vis);
protected:
private:
};
#endif //~_ELEMENT_H_
//Element.cpp
#include "Element.h"
#include "Visitor.h"
#include <iostream>
using namespace std;
Element_Person::Element_Person()
{
}
Element_Person::~Element_Person()
{
}
void Element_Person::Accept(Visitor_Action* vis)
{
}
ConcreteElementA_Women::ConcreteElementA_Women()
{
}
ConcreteElementA_Women::~ConcreteElementA_Women()
{
}
void ConcreteElementA_Women::Accept(Visitor_Action* vis)
{
cout<<"visiting ConcreteElementA..."<<endl;
vis->VisitConcreteElementA(this);
}
ConcreteElementB_Men::ConcreteElementB_Men()
{
}
ConcreteElementB_Men::~ConcreteElementB_Men()
{
}
void ConcreteElementB_Men::Accept(Visitor_Action* vis)
{
cout<<"visiting ConcreteElementB..."<<endl;
vis->VisitConcreteElementB(this);
}
// main.cpp
#include "Element.h"
#include "Visitor.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
Visitor_Action* visl = new ConcreteVisitorA_Lovesick(); // 失恋
Element_Person* elma = new ConcreteElementA_Women(); // 女人
elma->Accept(visl);
Element_Person* elmb = new ConcreteElementB_Men(); // 男人
elmb->Accept(visl);
Visitor_Action* vism = new ConcreteVisitorB_Marriage(); // 结婚
Element_Person* elma1 = new ConcreteElementA_Women(); // 女人
elma1->Accept(vism);
Element_Person* elmb1 = new ConcreteElementB_Men(); // 男人
elmb1->Accept(vism);
return 0;
}
正如前面所说,如果现在我需要增加一个对于看见“小强”的态度,就只需要增加一个Visitor_Action的子类,不需要改动其他类的任何代码。满足OCP原则。
Visitor模式可以使得Element在不修改自己的同时增加新的操作,但是这也带来了至少以下的两个显著问题:
1) 破坏了封装性。Visitor模式要求Visitor可以从外部修改Element对象的状态,这一般通过两个方式来实现:a)Element提供足够的public接口,使得Visitor可以通过调用这些接口达到修改Element状态的目的;b)Element暴露更多的细节给Visitor,或者让Element提供public的实现给Visitor(当然也给了系统中其他的对象),或者将Visitor声明为Element的friend类,仅将细节暴露给Visitor。但是无论那种情况,特别是后者都将是破坏了封装性原则(实际上就是C++的friend机制得到了很多的面向对象专家的诟病)。
2) ConcreteElement的扩展很困难:每增加一个Element的子类,就要修改Visitor的
接口,使得可以提供给这个新增加的子类的访问机制。从上面我们可以看到,或者增加一个用于处理新增类的Visit()接口,或者重载一个处理新增类的Visit()操作,或者要修改RTTI方式实现的Visit()实现。无论那种方式都给扩展新的Element子类带来了困难。