访客模式解释

Tri*_*a N 25 c++ visitor

所以我已经阅读了有关访客模式的所有文档,我仍然非常困惑.我从另一个问题中得到了这个例子,有人能帮我理解吗?例如,我们何时使用访客设计模式?我想我可能已经理解了一些,但我只是无法看到更大的图景.我如何知道何时可以使用它?

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);
Run Code Online (Sandbox Code Playgroud)

das*_*ght 33

访客模式用于实现双重调度.简而言之,它意味着执行的代码取决于两个对象的运行时类型.

当您调用常规虚函数时,它是单个调度:执行的代码片段取决于单个对象的运行时类型,即您要调用的虚拟方法.

使用访问者模式,被调用的方法最终取决于两个对象的类型 - 实现该对象的对象equipmentVisitor的类型,以及您调用的对象的类型accept(即equipmentVisited子类).

还有其他方法可以在C++中实现双重调度.Scott Meyer的"更有效的C++"第31项深入探讨了这一主题.


小智 13

我认为访客模式的名称是非常不幸的.而不是访问者这个词我会说Functor或Operator而不是'visit'我会说'apply'.

我对访客模式的理解如下:

在模板元编程(STL/BOOST)(编译时绑定)中,您可以通过函数对象(Functors)实现(正交设计)操作与结构的分离.例如,

template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
Run Code Online (Sandbox Code Playgroud)

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:
  //....
}
Run Code Online (Sandbox Code Playgroud)

从公共接口中删除尽可能多的函数(只要它们可以根据同一公共接口的非提取函数实现),并将操作表示为来自新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: 
     //....
 }
Run Code Online (Sandbox Code Playgroud)

//现在你有N(= 3)在同一层级类(A,B,C)和M操作,或在Functor_or_Operator层次结构类为代表的功能,您需要实现从Functor_or_Operator的每一个操作是如何工作的每N*M个定义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*) {}
  }
Run Code Online (Sandbox Code Playgroud)