访问者模式意图在不改变目标对象类结构的情况下,扩展对象类的行为。新扩展的行为均被封装成类对象的形式来动作。应用该模式时,往往目标类系与Visitor类系是两个不同的类系,它们配合工作但维护是分开的,互不影响。每次扩展一个新行为时,需要新增加一个Visitor派生类。而目标类系只需要接受Visitor对象即可。模式的类关系图参考如下:
模式编码结构参考如下:
1 namespace visitor 2 { 3 class Target; 4 class IVisitor 5 { 6 public: 7 // some code here........ 8 virtual void doSomething(Target* pTarget) { 9 // do something here........ 10 // such as: if (nullptr != pTarget) pTarget->........ 11 } 12 13 };//class IVisitor 14 15 class ConcreteVisitor1 : public IVisitor 16 { 17 public: 18 // some code here........ 19 virtual void doSomething(Target* pTarget) override { 20 // do something here........ 21 // such as: if (nullptr != pTarget) pTarget->........ 22 } 23 24 };//class ConcreteVisitor1 25 26 class ConcreteVisitor2 : public IVisitor 27 { 28 public: 29 // some code here........ 30 virtual void doSomething(Target* pTarget) override {// do something here........ 31 // such as: if (nullptr != pTarget) pTarget->........ 32 } 33 34 };//class ConcreteVisitor2 35 36 class Target 37 { 38 public: 39 // some code here........ 40 virtual void accept(IVisitor* pVisitor) { 41 // do something here........ 42 // such as: 43 if (nullptr != pVisitor) { 44 pVisitor->doSomething(this); 45 } 46 } 47 48 };//class Target 49 50 class ConcreteTarget1 : public Target 51 { 52 public: 53 // some code here........ 54 virtual void accept(IVisitor* pVisitor) override { 55 // do something here........ 56 // such as: 57 if (nullptr != pVisitor) { 58 pVisitor->doSomething(this); 59 } 60 } 61 62 };//class ConcreteTarget1 63 64 class ConcreteTarget2 : public Target 65 { 66 public: 67 // some code here........ 68 virtual void accept(IVisitor* pVisitor) override { 69 // do something here........ 70 // such as: 71 if (nullptr != pVisitor) { 72 pVisitor->doSomething(this); 73 } 74 } 75 76 };//class ConcreteTarget2 77 78 }//namespace visitor
访问者模式在不改动原有类结构的情况下即可扩展类对象的新的行为且不改变原有结构,这在对象类结构比较固定且比较完善,但又需要或有可能会扩展一些特殊的行为操作时特别有用。尤其在设计工具库等场合,可适应考虑为将来可能的新业务变动预留接口。其实有玩过objective-c的人,在看到该模式时,可能会想到objective-c语言的一个技术:在使用别人封装的对象时,可以重新为该对象扩展新的接口,同样也是不需要改变别人封装的对象。其实这个技术与该模式的意图是类似的。
访问者模式的好处是显而易见的,其允许我们自由扩展新的行为特性,但这也是其重大缺点,因为势必会破坏对象的封装特性(当然,像C++这样的语言还有friend可用,对于该特性的破坏还有一定的挽回余地,但friend其实质上就已是在破坏封装特性了)。另外,由于Visitor类系的引入,系统中维护的类将增多,且无形当中也会增加一定量的Visitor类系的实例对象。再者,新扩展一个Target类系类型时,则有可能会让Visitor类系产生较大的改动(这个可能还需要视实际的项目设计者的设计方案而定)。