为什么我们需要访问者设计模式中的访问方法?

时间:2012-07-30 13:14:39

标签: design-patterns

为什么我们在访问者DP中同时需要acceptvisit个功能?如果我们采用典型的例子:

class Visitor {
  visit(A a) { }
  visit(B b) { }
}

interface Element {
  accept(Visitor v);
}

class A implements Element {
  accept(Visitor v) {
    v.visit(this); // will call visit(A)
  }
}

class B implements Element {
  accept(Visitor v) {
    v.visit(this); // will call visit(B)
  }
}

要使用访问者DP,我们的v实例Visitor以及e的实例Element,我们会这样做:

e.visit(v)

简单地调用

v.visit(e)

那为什么我们不能简单地进行第二次调用并绕过中介功能呢?由于我认为GoF并不愚蠢,我想我错过了一些东西。它是什么?

2 个答案:

答案 0 :(得分:3)

Here是访问者模式的绝佳参考,其中提到了以下内容:

  

当在程序中调用accept()方法时,它的实现   是根据两者选择的:

     
      
  • 元素的动态类型。
  •   
  • 访客的静态类型。
  •   
     

当调用关联的visit()方法时,它的实现是   根据两者选择:

     
      
  • 访客的动态类型。
  •   
  • 从accept()方法的实现中已知的元素的静态类型,它与   动态类型的元素。 (作为奖励,如果访客无法处理   给定元素类型的参数,然后编译器将捕获   错误。)
  •   
     

因此,选择了visit()方法的实现   两者:

     
      
  • 元素的动态类型。
  •   
  • 访客的动态类型。
  •   

然后他们继续提到以下内容:

  

这有效地实现了双重派遣......

     

通过这种方式,可以编写单个算法来遍历图形   元素和许多不同类型的操作都可以执行   在那次遍历期间,提供不同类型的访客   基于两者的动态类型与元素交互   元素和访客。

可以在Java汽车示例中看到:

class Car implements CarElement {
    CarElement[] elements;
    // ...
    public void accept(CarElementVisitor visitor) {     
        for(CarElement elem : elements) {
            elem.accept(visitor);
        }
        visitor.visit(this); 
    }
}

总而言之,在您的示例中,您不会从原始DP实现中获得太多好处,但如果示例更复杂,例如它的Composite具有几个内部实现的Element(如Java)上面的汽车示例),然后它可以将访问者行为应用于其部分或全部内部元素。

根据对原始问题的评论,此模式分为两部分:

  1. 模式的最初动机:访问复杂的对象结构并对其执行操作,而不更改正在访问的类接口。
  2. 如何实现模式:正如您所提到的那样是双重调度。
  3. 我强烈推荐以下设计模式书,因为它真正简化了许多概念。 GoF书有时太过学术化了。

    Head First Design Patterns

    根据这本书,以下是使用访客的利弊:

    (在所用示例的上下文中)

    赞成

    • 允许您在不更改结构本身的情况下向Composite结构添加操作
    • 添加新操作相对容易
    • 访问者执行的操作代码是集中的

    CON外

    • 复合课程'使用访问者时,封装会被破坏。
    • 由于涉及遍历功能,因此更改复合结构更加困难

答案 1 :(得分:0)

它很简单(但也许有点令人困惑),访问者模式的重点是将访问者与访问者分开。

accept()允许被访问者选择它将向某个类型的访问者公开的行为。

布拉迪说同样的话,我只是想用更少的话说出来