已经知道,使用 Visitor有这样那样的不便。Loki为了避免这些提供了两个方案,之一就是Acyclic的类库化。
class BaseVisitor
...{
public:
virtual ~BaseVisitor()...{};
};
template <class T,typename R = void>
class Visitor
...{
public:
typedef R ReturnType;
virtual ReturnType Visit(T&) = 0;
};你的访问者必须继承这两个类,具体的情况可能是:
class MyVisitor
:public BaseVisitor
,public Visitor<A>
,public Visitor<B>
...{
public:
void Visit(A&); //visit A
void Visit(B&); //visit B
}使用起来很简单,记得继承和根据自己的特定类编写特定Visit方法就可以了。对于Visitable:
template <typename R = void>
class BaseVisitable
...{
public:
typedef R ReturnType;
virtual ~BaseVisitable()...{};
virtual ReturnType Accept(BaseVisitor&) = 0;
protected:
template <class T>
static ReturnType AcceptImpl(T& visited,BaseVisitor& guest)
...{
if (Visitor<T>* p = dynamic_cast<Visitor<T>*>(&guest))
...{
return p->Visit(visited);
}
return ReturnType();
}
};
#define DEFINE_VISITABLE()
virtual ReturnType Accept(BaseVisitor& guest) 
...{return AcceptImpl(*this,guest);}你已经猜到,你的Visitable必须继承BaseVisitable,但是,Visit是要动态转换的,这个调用地方必须在子类中,放在基类中动态转换没有任何意义。为了提供侵入用户类的方便手段,loki定义了DEFINE_VISITABLE()宏,如果你对MFC有一定了解的话,你一定会觉得这种手法很熟悉。
当然,侵入宏只是为了只是动态转换,如果你需要,自己写也没什么,你还可以获得应有的自由度。
这样,一般的使用BaseVisitable的方法是:
class A :public BaseVisitable<>
...{
public:
DEFINE_VISITABLE()
};把宏替换为它的定义代码,修改Accept的实现就可以自定义AcceptImpl的行为。
本文介绍了一种改进的访问者模式实现——Acyclic类库化。通过定义BaseVisitor和BaseVisitable基类,并利用模板和动态转换,使得访问者模式更加灵活且易于使用。文章详细解释了如何自定义Visit方法及如何使用户类成为可被访问的对象。
1538

被折叠的 条评论
为什么被折叠?



