本文是学习刘伟技术博客和《设计模式-可复用面向对象软件的基础》笔记,博客链接:http://blog.youkuaiyun.com/lovelion/article/details/17517213
主要是对博客和书本做提炼和记录,更多是对设计模式的基础框架学习,细节将略去,侧重对每个设计模式框架的理解。
我应该理解和掌握的:
1)能够画出这个设计模式的架构框图;
2)能够根据架构框图写出对应的伪代码;
3)这个模式的应用场景,主要优缺点。
1.访问者模式
发现变化并封装之。说到看电视,爸妈比较喜欢看非诚勿扰,弟妹比较喜欢看综艺节目,我比较喜欢看电影。从某种程度上讲也可以比作是访问者模式,电视是固定不变的,而我们对他的访问是变化的。访问者模式是一种较为复杂的模式,它包含访问者和被访问者两个主要元素。在使用访问者模式时,被访问的元素通常不是单独存在,他们存储在一个集合中,这个集合被称为对象结构,访问者通过遍历对象结构实现对其中存储的元素逐个操作。
(1)定义
访问者模式:表示一个作用于某对象结构中的各元素操作。他使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
1) 访问者模式结构图
2) 参与者
a)Vistor(访问者):为该对象结构中的ConcreteElement的每一个类声明一个访问操作。该操作的名字或者参数类型可以知道需要访问哪一个具体元素。
b)ConcreteVistor(具体访问者):实现抽象访问者声明的操作;
c)Element(抽象元素):定义一个Accept操作,它以一个访问者为参数。
d)ConcreteElement(具体元素):实现Accept操作,该操作以一个访问者为参数。
e)ObjectStructure(结构对象):能枚举他的元素;可以提供一个高层次接口以允许访问者访问它的元素。
3) 看图写代码
/*
** FileName : VisitorPattern
** Author : lin005
** Date : 2015/02/10
** Description : More information, please go to http://blog.youkuaiyun.com/amd123456789
*/
#include<iostream>
#include<list>
using namespace std;
class Element;
//抽象访问者类,声明访问元素的接口
class Vistor
{
public:
virtual void visitConcreteElementA(Element* A) = 0;
virtual void visitConcreteElementB(Element* B) = 0;
};
//抽象元素类,声明accept接口
class Element
{
public:
virtual void Accept(Vistor*) = 0;
};
//具体元素类
class ConcreteElementA : public Element
{
public:
ConcreteElementA(){}
//实现accept接口
void Accept(Vistor* v)
{
v->visitConcreteElementA(this);
}
};
//具体元素类
class ConcreteElementB : public Element
{
public:
ConcreteElementB(){}
//实现accept接口
void Accept(Vistor* v)
{
v->visitConcreteElementB(this);
}
};
//具体访问者A
class ConcreteVisitorA : public Vistor
{
public:
ConcreteVisitorA(){}
//实现访问接口
void visitConcreteElementA(Element* A)
{
cout<<"Visitor A is visiting ConcreteElementA"<<endl;
}
//实现访问接口
void visitConcreteElementB(Element* B)
{
cout<<"Visitor A is visiting ConcreteElementB"<<endl;
}
};
//具体访问者B
class ConcreteVisitorB : public Vistor
{
public:
ConcreteVisitorB(){}
void visitConcreteElementA(Element* A)
{
cout<<"Visitor B is visiting ConcreteElementA"<<endl;
}
void visitConcreteElementB(Element* B)
{
cout<<"Visitor B is visiting ConcreteElementB"<<endl;
}
};
//对象结构,持有元素集合
class ObjectStructure
{
public:
ObjectStructure(){}
//增加元素
void attach(Element* e)
{
m_list.push_back(e);
}
//删除元素
void remove(Element* e)
{
m_list.remove(e);
}
//接受访问者对元素进行遍历访问
void Accept(Vistor* v)
{
list<Element*>::iterator it = m_list.begin();
while(it != m_list.end())
{
(*it)->Accept(v);
++it;
}
}
private:
list<Element*> m_list;//元素集合
};
//客户端测试
#define SAFE_DELETE(p) if(p){delete p; p = NULL;}
int main()
{
//创建结构对象
ObjectStructure* p_object = new ObjectStructure();
//创建元素对象
Element* pA = new ConcreteElementA();
Element* pB = new ConcreteElementB();
p_object->attach(pA);
p_object->attach(pB);
//创建访问者
Vistor* vA = new ConcreteVisitorA();
Vistor* vB = new ConcreteVisitorB();
//接受访问者访问
p_object->Accept(vA);
p_object->Accept(vB);
SAFE_DELETE(vA);
SAFE_DELETE(vB);
SAFE_DELETE(pA);
SAFE_DELETE(pB);
SAFE_DELETE(p_object);
return 0;
}
(2)总结
1) 优点
a)访问者模式使得易于增加新的操作。无需修改源码码,只需要增加新的访问者子类。
b)将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个元素类中。简化了元素类,类的职责更加清晰。
c)让用户能够在不修改现有元素类层次结构的情况下,定义作用于该层次结构的操作。
2) 缺点
a)增加新的ConcreteElement类很困难。在访问者模式中,每增加一个新的元素类都意味着要在抽象访问者中增加一个新的抽象操作,并在具体访问者中实现它,违反开闭原则。
b)破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,意味着元素对象有时候必须暴露一些自己的内部状态和操作,否则无法供访问者访问。
(3)适用场景
1)一个对象结构包含很多类对象,他们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。访问者模式针对每个具体的类型都提供了一个访问操作,不同类型的对象可以有不同的操作。
2) 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。
3)需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作污染这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。