在 OOP 开发中,需求变更是家常便饭。系统原型设计好之后,客户的新需求随时可能到来,最常见的应对方式是不断添加新类或新方法,结果设计越来越难以封闭,补丁打了一层又一层。

访问者模式(Visitor Pattern)的思路是:把需要变动或扩展的操作封装到一个独立的访问者类中,由被访问的元素类提供一个 Accept 接口。这样,在不改变数据结构(Element)的前提下,可以通过扩展访问者子类来添加新操作,让设计在对扩展开放的同时对修改保持封闭。

Double Dispatch

访问者模式涉及到 Double Dispatch(双分派)问题。具体调用哪一个 Accept 方法,取决于两个因素:

  1. Accept 是多态操作,需要由具体的 Element 子类决定。
  2. Accept 的参数类型是 Visitor,需要由实际的 ConcreteVisitor 来决定调用哪个 Visit 方法。

因此需要派发两次,访问者模式正是 Double Dispatch 的一种典型实现。关于 Double Dispatch 的详细阐述,可参考:http://my.oschina.net/kkkkkkkkkkkkk/blog/671305

此外,Visitor 可以为每个 Element 单独定义一个访问接口,也可以通过重载或 RTTI 来简化接口设计。

示例代码

#include "PublicHeaders.h"
                
                #pragma once
                class Visitor;
                
                
                class Element
                {
                public:
                	void Print()
                	{
                		cout << " this is element" << __FUNCTION__ << endl;
                	}
                	/**
                	* @brief the interface of visitor's visit
                	*/
                	virtual void Accept(Visitor *visitor) = 0;
                };
                
                class Visitor
                {
                public:
                	virtual void VisitElementA(Element*ele) = 0;
                
                };
                
                
                
                
                class ConCreateVisitor :public Visitor
                {
                public:
                
                	void VisitElementA(Element *ele)
                	{
                		ele->Print();
                	}
                };
                
                class ConCreateElementA :public Element
                {
                public:
                	virtual void Accept(Visitor *visitor)override
                	{
                		visitor->VisitElementA(this);
                	}
                };
                
                
                
                
                void testVisitor()
                {
                	Element *ele = new ConCreateElementA;
                	Visitor *vis = new ConCreateVisitor;
                
                	ele->Accept(vis);
                
                }