在 OOP 开发中,需求变更是家常便饭。系统原型设计好之后,客户的新需求随时可能到来,最常见的应对方式是不断添加新类或新方法,结果设计越来越难以封闭,补丁打了一层又一层。
访问者模式(Visitor Pattern)的思路是:把需要变动或扩展的操作封装到一个独立的访问者类中,由被访问的元素类提供一个 Accept 接口。这样,在不改变数据结构(Element)的前提下,可以通过扩展访问者子类来添加新操作,让设计在对扩展开放的同时对修改保持封闭。
Double Dispatch
访问者模式涉及到 Double Dispatch(双分派)问题。具体调用哪一个 Accept 方法,取决于两个因素:
Accept是多态操作,需要由具体的 Element 子类决定。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);
}