首先我们拥有一个由许多对象构成的对象结构,这些对象的类都拥有一个accept方法用来接受访问者对象;访问者是一个接口,它拥有一个visit方法,这个方法对访问到的对象结构中不同类型的元素作出不同的反应;在对象结构的一次访问过程中,我们遍历整个对象结构,对每一个元素都实施accept方法,在每一个元素的accept方法中回调访问者的visit方法。
访问者模式使得我们可以在传统的单分派语言(如Java和C++)中模拟双分派(dual dispatch)技术。优点就是增加新的操作很容易(传入不同的visitor),缺点是使得增加新的具体类型变的困难了。
原始实现:
- 消息Visitable接口定义一个结构方法:accept(visitor v) { v.visit(this); }
- 访问者Visitor接口定义处理方法:visitor(具体类型) { 具体逻辑 }
- 使用者调用:具体类型.accept(v);
这个结构缺点在于新增具体类型,还得修改访问者接口
Acyclic visitor模式实现:消除声明间的循环依赖,每个访问者声明一种专属接口
C++利用泛型实现Acyclic visitor模式,以减少多态类个数:
- 声明BaseVisitable基类接口,提供纯虚Accept(BaseVisitor&)方法
- 声明BaseVisitor基类接口 , 空类即可, 但要求
所有visitor类都要实现这个,否则Visitable没法使用统一的Accept方法 - 提供DEFINE_VISITABLE宏,加入Accept泛型实现方法,会根据类型Visitor<T>调用对应的visit(T& this)方法
- Visitor<T>接口全部继承自BaseVisitor,每个接口提供纯虚visit(T&)方法
- 具体访问者要继承Visitor<T>基类,实现具体visit<T>方法
其中一个问题是accept泛型实现中,要根据T将BaseVisitor转换为对应Visitor<T>才可以进行visit方法调用。一种方法是使用dyamic_cast强制转换,还有一种优化是使用hash表:
- 声明BaseVisitable基类接口,声明纯虚Accept(VisitorBase* )方法
- 声明VisitorBase 基类接口,可以声明纯虚GetFunc方法
- BASE_VISITOR_DECLARE 基类使用的宏,提供GetFunc(key)方法实现
- VISITOR_DECLARE 声明继承顺序, 提供GetFunc(key)方法实现,该方法先查本身再查基类
- VISITOR_IMPLEMENT 调用__RegisterVisitFunc方法向hash表注册所有visit方法(key, visit方法指针)
- BASE_DEFINE_VISITABLE 基类使用的宏, 提供 Accept(VisitorBase*)方法,会使用visitor的GetFunc方法获得对于的visit指针,从而进行调用
- DEFINE_VISITABLE 声明继承顺序, 提供 Accept(VisitorBase*)方法,同样先调用自身方法,再调用基类
抢沙发
还没有评论,你可以来抢沙发