设计模式---行为变化模式之访问器模式(Visitor)
一:概念
访问者模式,是行为模式之一,它分离对象的数据和行为,使用Visitor模式,可以不修改已有类的情况下,增加新的操作角色和职责。
二:动机
在软件构建的过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法)。如果直接在类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计。
如何在不更改类层次结构的前提下,在运行时根据需要透明地为类层次结构上的各个类动态添加新的操作,从而避免上述问题?
三:代码讲解
(一)原代码
#include <iostream> using namespace std; class Visitor; class Element { public: virtual void Func1() = 0; virtual ~Element(){} }; class ElementA : public Element { public: void Func1() override{ //... } }; class ElementB : public Element { public: void Func1() override{ //*** } };
需求:想要增加一个新的功能
#include <iostream> using namespace std; class Visitor; class Element { public: virtual void Func1() = 0; virtual void Func2(int data)=0; //定义虚方法,后面继承父类的都要一一实现 virtual void Func3(int data)=0; //... virtual ~Element(){} }; class ElementA : public Element { public: void Func1() override{ //... } void Func2(int data) override{ //... } }; class ElementB : public Element { public: void Func1() override{ //*** } void Func2(int data) override { //*** } };
这不是一个好的方法,在部署后,我们再次修改,此时的代价是十分高的,违背了开闭原则
(二)visitor模式---->前提:能够预料到未来可能会为这整个类层次结构添加新的操作,但是我不知道要加多少操作,什么操作
1.预先设计Element基类
class Visitor; class Element { public: virtual void accept(Visitor& visitor) = 0; //第一次多态辨析 //accept方法为将来埋下伏笔,将来要添加新的功能,加到这里去找他,进行绑定visitor virtual ~Element(){} };
2.完善visitor基类
class Visitor{ public: virtual void visitElementA(ElementA& element) = 0; //针对每一个子类生成一个方法对应 virtual void visitElementB(ElementB& element) = 0; virtual ~Visitor(){} };
3.element子类实现
class ElementA : public Element { public: void accept(Visitor &visitor) override { visitor.visitElementA(*this); } }; class ElementB : public Element { public: void accept(Visitor &visitor) override { visitor.visitElementB(*this); //第二次多态辨析 } };
=========================上面实现了:预先的设计了我将来可能会增加的新的操作=============================
4.将来,要为前面的整个类层次结构添加新的操作,添加visitor子类,在子类中扩展
//扩展1 将来 class Visitor1 : public Visitor{ public: void visitElementA(ElementA& element) override{ cout << "Visitor1 is processing ElementA" << endl; } void visitElementB(ElementB& element) override{ cout << "Visitor1 is processing ElementB" << endl; } }; //扩展2 将来的将来 class Visitor2 : public Visitor{ public: void visitElementA(ElementA& element) override{ cout << "Visitor2 is processing ElementA" << endl; } void visitElementB(ElementB& element) override{ cout << "Visitor2 is processing ElementB" << endl; } };
5.操作绑定
int main() { Visitor2 visitor; ElementB elementB; elementB.accept(visitor);// double dispatch 将visitor2中的新的visitElementA操作添加到elementB中 ElementA elementA; elementA.accept(visitor); //将Visitor2中新的visitElementB新操作添加到了elementA中 return 0; }
四:模式定义
表示一个作用与某对像结构中的各元素的操作。使得可以在不改变(稳定)各元素的类的前提下定义(扩展)作用于这些元素的新操作(变化)。
——《设计模式》GoF
五:类图(结构)
visitor要预先知道(依赖于)我们具体的ELement子类,所以我们要提前设置好其子类,之后基本不会修改我们修改的只有visitor扩展子类。
所以Element子类是稳定的
(必须提前确定下来,但是常常确定不了,我们一增加element子类,visitor基类就要做出相应改变,子类也是,全部的稳定性都混乱了,打破了开闭原则,全部都要重新编译),
visitor子类是变化的
六:要点总结
(一)Vistor模式通过所谓的双重分发(double dispatch)来实现在不更改(不添加新的操作-编译时)Element类层次结构的前提下,在运行时透明地为类层次结构上的各个类动态添加新的操作(支持变化)。
(二)所谓双重分发即Vistor模式中间包括了两个多态分发(注意其中的多态机制):第一个accept方法的多态解析;第二个为visitElementX方法的多态辨析。
(三)Visitor模式最大的缺点在于扩展类层次结构(增添新的Element子类),会导致Visitor类的改变。因此Visitor模式适用于“Element类层次结构稳定,而其中的操作却进场面临频繁改动”。
七:案例实现(公园功能扩展)
比如有一个公园,有一到多个不同的组成部分;多个公园,每个公园存在多个访问者:清洁工负责打扫公园的部分,公园的管理者负责检点各项事务是否完成,上级领导可以视察公园,扩建等等。
也就是说,对于同一个公园,不同的访问者有不同的行为操作,而且访问者的种类也可能需要根据时间的推移而变化(行为的扩展性)。
根据软件设计的开闭原则(对修改关闭,对扩展开放),我们怎么样实现这种需求呢?
(一)实现访问者基类
class ParkElement; class Visitor //Visitor是针对每个element的子类,其方法也是针对 { public: virtual void visitParkA(ParkElement* park) = 0; virtual void visitParkB(ParkElement* park) = 0; virtual ~Visitor(){} };
(二)实现公园基类
class ParkElement { public: void Clean() { cout << "clean part" << endl; } void Play() { cout << "play in part" << endl; } virtual void accept(Visitor* v) = 0; };
(三)实现子类具体公园
class ParkA:public ParkElement { public: virtual void accept(Visitor* v) { v->visitParkA(this); } }; class ParkB :public ParkElement { public: virtual void accept(Visitor* v) { v->visitParkB(this); } };
(四)针对具体公园子类扩展功能
//扩展,这里扩展了两个功能 class Visitor1 :public Visitor { public: virtual void visitParkA(ParkElement* park) { cout << "leader check parkA health" << endl; } virtual void visitParkB(ParkElement* park) { cout << "leader check parkB health" << endl; } }; class Visitor2 :public Visitor { public: virtual void visitParkA(ParkElement* park) { cout << "leader extend parkA area" << endl; } virtual void visitParkB(ParkElement* park) { cout << "leader extend parkB area" << endl; } };
(五)进行扩展绑定
void main() { Visitor1 visitor; ParkA pA,pB; pA.accept(&visitor); pB.accept(&visitor); system("pause"); return; }
#include <iostream> #include <list> #include <string> using namespace std; class ParkElement; class Visitor //Visitor是针对每个element的子类,其方法也是针对 { public: virtual void visitParkA(ParkElement* park) = 0; virtual void visitParkB(ParkElement* park) = 0; virtual ~Visitor(){} }; class ParkElement { public: void Clean() { cout << "clean part" << endl; } void Play() { cout << "play in part" << endl; } virtual void accept(Visitor* v) = 0; }; class ParkA:public ParkElement { public: virtual void accept(Visitor* v) { v->visitParkA(this); } }; class ParkB :public ParkElement { public: virtual void accept(Visitor* v) { v->visitParkB(this); } }; //扩展 class Visitor1 :public Visitor { public: virtual void visitParkA(ParkElement* park) { cout << "leader check parkA health" << endl; } virtual void visitParkB(ParkElement* park) { cout << "leader check parkB health" << endl; } }; class Visitor2 :public Visitor { public: virtual void visitParkA(ParkElement* park) { cout << "leader extend parkA area" << endl; } virtual void visitParkB(ParkElement* park) { cout << "leader extend parkB area" << endl; } }; void main() { Visitor1 visitor; ParkA pA,pB; pA.accept(&visitor); pB.accept(&visitor); system("pause"); return; }