所以我已经阅读了有关访客模式的所有文档,我仍然非常困惑。我从另一个问题中得到了这个例子,有人能帮我理解吗?例如,我们何时使用访客设计模式?我想我可能已经理解了一些,但我只是无法看到更大的图景。我如何知道何时可以使用它?
class equipmentVisited
{
virtual void accept(equipmentVisitor* visitor) = 0;
}
class floppyDisk : public equipmentVisited
{
virtual void accept(equipmentVisitor* visitor);
}
class processor : public equipmentVisited
{
virtual void accept(equipmentVisitor* visitor);
}
class computer : public equipmentVisited
{
virtual void accept(equipmentVisitor* visitor);
}
class equipmentVisitor
{
virtual void visitFloppyDisk(floppyDisk* );
virtual void visitProcessor(processor* );
virtual void visitComputer(computer* );
}
// Some additional classes inheriting from equipmentVisitor would be here
equipmentVisited* visited;
equipmentVisitor* visitor;
// Here you initialise visited and visitor in any convenient way
visited->accept(visitor);
答案 0 :(得分:32)
访客模式用于实施double dispatch。简单来说,这意味着执行的代码取决于两个对象的运行时类型。
当你调用常规的虚函数时,它是一个单一的调度:执行的代码片段取决于单个对象的运行时类型,即虚拟方法的一个你在打电话。
使用访问者模式,被调用的方法最终取决于两个对象的类型 - 实现equipmentVisitor
的对象的类型,以及您调用的对象的类型{{1} }(即accept
子类)。
还有其他方法可以在C ++中实现双重调度。 Scott Meyer的"More Effective C++"第31项深入讨论了这个问题。
答案 1 :(得分:13)
我认为访客模式的名称非常不幸。 而不是访问者这个词我会说Functor或Operator而不是'visit'我会说'apply'。
我对访客模式的理解如下:
在模板元编程(STL / BOOST)(编译时绑定)中你可以实现(正交设计) 通过函数对象(Functors)将操作与结构分离。 例如在
中template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
comp是一个仿函数/运算符,以非常通用的方式表示“小于”运算,因此您不必具有许多sort函数变体:
对于访问者模式,您希望实现类似的功能,但在运行时(延迟)绑定的情况下:
您希望简化A的界面,您希望保留未来扩展的可能性(使用A的新操作),并且您希望在这些扩展的情况下实现A的接口的稳定性。
从最初的'胖'课程:
class A
{
public:
virtual void function_or_operation_1();//this can be implemented in terms of public interface of the other functions
virtual void function_or_operation_2();
//..etc
virtual void function_or_operation_N();
public:
//stable public interface, some functions of procedures
private:
//....
}
从公共接口中删除尽可能多的功能(只要它们可以根据同一公共接口的非提取功能实现) 并将操作表示为来自新Functor层次结构的仿函数对象或对象:
通过使用前向声明的Functor_or_Operator具有非常通用的接口来减少基类A中的函数数量:
class Functor_or_Operator;
class A
{
public:
virtual void apply(Functor_or_Operator*);//some generic function operates on this objects from A hierarchy
//..etc
public:
//stable public interface, some functions
private:
//....
}
//现在,您在A层次结构(A,B,C)中有N(= 3)个类,并且Functor_or_Operator层次结构中的类表示M个操作或函数 您需要实现N * M定义,以了解Functor_or_Operator中的每个操作如何对A层次结构中的每个类起作用。 最重要的是,你可以在不改变类'A'的界面的情况下完成它。 在引入使用A层次结构对象的新操作或函数时,新增加的情况下,类'A'的声明变得非常稳定 或者在A层次结构中有新的派生类。 在添加的情况下A的稳定性(A没有变化)对于避免代价高昂(有时甚至是不可能)的软件重新编译很重要,这些软件包括许多地方的A标题。
对于A层次结构中的每个新类,您扩展了基本Functor_or_Operator的定义,您添加了新的实现文件,但您永远不需要触及基类A的标头(通常是接口或抽象类)。
class Functor_or_Operator
{
virtual void apply(A*)=0;
virtual void apply(B*)=0;
virtual void apply(C*)=0;
}
void A::apply(Functor_or_Operator* f)
{ f->apply(this);} //you need this only if A is not abstract (it is instantiable)
class B:public A
{
public:
void apply(Functor_or_Operator* f) { f->apply(this);} //dynamic dispatch , you call polymhorphic Functor f on this object
//..the rest of B implementation.
}
class C:public A
{
public:
void apply(Functor_or_Operator* f) { f->apply(this);} //dynamic dispatch , you call polymorfic Functor f on this object
//..the rest of C implementation.
}
class Functor_or_Operator_1:public Functor_or_Operator
{
public:
//implementations of application of a function represented by Functor_or_Operator_1 on each A,B,C
void apply(A*) {}//( only if A is instantiable,not an abstract class)
void apply(B*) {}
void apply(C*) {}
}
class Functor_or_Operator_2:public Functor_or_Operator
{
public:
//implementations of application of a function represented by Functor_or_Operator_2 on each A,B,C
void apply(A*) {}//( only if A is instantiable,not an abstract class)
void apply(B*) {}
void apply(C*) {}
}