[设计模式]行为模式-访问者(C++描述)
second60 20180603
1. 访问者模式定义
访问者模式:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
将数据结构和数据操作分离的设计模式。
2. 访问者模式结构图
分析:
Vistor抽象访问者角色:为该对象结构中具体元素角色声明一个访问操作接口。该操作接口的名字和参数标识请求给具体访问者的具体元素角色,这样访问者就可以通过该元素角色的特定接品直接访问它。
ConcreteVisitor具体访问者角色,实现Visitor声明的接口
Elememt定义一个接受访问操作accept(), 它以一个访问者Vistor作为参数。
ConcreteElement具体元素:实现了抽象元素Element所定义的接受的操作接口。
ObjectStructure结构对象:能枚举它的元素,可以接口允许访问者访问它的元素。
3. 代码实现
class Element; //访问者父类 class Visitor { public: virtual ~Visitor(){} virtual void VisitConcreteElementA( Element *elm ) = 0; virtual void VisitConcreteElementB( Element *elm ) = 0; protected: Vistor(){} }; // 访问者A class ConcreteVisitorA: public Visitor { public: ConcreteVisitorA(){} virtual ~ConcreteVisitorA(){} virtual void VisitConcreteElementA( Element *elm ){} virtual void VisitConcreteElementB( Element *elm ){} }; // 访问者B class ConcreteVisitorB: public Visitor { public: ConcreteVisitorB(){} virtual ~ConcreteVisitorB(){} virtual void VisitConcreteElementA( Element *elm ){} virtual void VisitConcreteElementB( Element *elm ){} }; // 元素抽象类 class Element { public: virtual ~Element(){} virtual void Accept(Visitor *vis)=0; protected: Element(){} }; class ConcreteElementA:public Element { public: ConcreteElementA(){} ~ConcreteElementA(){} void Accept(Visitor* vis) { vis->VisitConcreteElementA(this); } }; class ConcreteElementB:public Element { public: ConcreteElementB(){} ~ConcreteElementB(){} void Accept(Visitor* vis) { vis->VisitConcreteElementB(this); } }; int main() { Visitor *vis = new ConcreteVisitorA(); Element *elm = new ConcreteElementA(); elm->Accept(vis); return 0; } // 改进版添加ObjectStructure对象 class ObjectStructure { public: ObjectStructure() { _elementMap = new std::map<string,Element*>; Element *elmA = new ConcreteElementA(); Element *elmB = new ConcreteElementB(); elementMap[“ElementA”] = elmA ; elementMap[“ElementB”] = elmB ; } ~ObjectStructure() { if(_elementMap) { map<string,Element*> iter = _elementMap->begin(); for(; iter != _elementMap->end(); ++iter) { Element* temPtr = iter->second(); if(tempPtr) { delete tempPtr; tempPtr = NULL; } _elementMap->erase(iter ++); } // _elementMap.clear(); delete _elementMap; } } std::map<string,Element*> *getMap() { return _elementMap; } private: std::map<string,Element*> *_elementMap; };
2.1 优点
1. 符合单一职责原则:凡是适用访问者模式的场景中,元素类中需要封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,使用访问者模式一方面符合单一职责原则,另一方面,因为被封装的操作通常来说都是易变的,所以当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展。
2. 扩展性良好:元素类可以通过接受不同的访问者来实现对不同操作的扩展。
3. 使得数据结构和操作解耦,使得操作集合可以独立变化
4. 添加新操作或新访问者会非常容易
5. 将各个元素的一组操作集中在一个访问者类当中
6. 使得类层次结构不改变的情况下,可以针对各个层次做出不同的操作,而不影响类层次结构。
2.2 缺点
1. 增加新元素会非常困难
2. 实现起来比较复杂,会增加系统复杂性
3. 破坏封装,为了让访问者获得所关心信息,元素类不得不暴露出一些内部的状态和结构。
3 适用场景
1. 对象结构比较稳定,经常需要在此对象结构上定义新的操作。
2. 需要对一个对象结构中的对象进行很多不同的且不相关的操作,而需要避免这些操作污染这些对象的类,不希望修改原有类。
4 总结
访问者模式是一个比较复杂的模式,在数据结构稳定的情况下,不同访问者可以拥有不同的操作,能在不改变现有逻辑的情况下,通过继承,来支持新的操作或访问者。