3

为什么我们需要在访问者 DP 中同时使用accept和函数?visit如果我们举一个典型的例子:

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,我们这样做:VisitoreElement

e.visit(v)

它只是调用

v.visit(e)

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

4

2 回答 2

3

是访问者模式的一个很好的参考,他们在其中提到了以下内容:

当在程序中调用 accept() 方法时,它的实现是基于以下两者来选择的:

  • 元素的动态类型。
  • 访问者的静态类型。

当调用关联的 visit() 方法时,它的实现是基于以下两者选择的:

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

因此,visit() 方法的实现是基于以下两种情况选择的:

  • 元素的动态类型。
  • 访问者的动态类型。

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

这有效地实现了双重调度......

这样,可以编写一个算法来遍历元素图,并且可以在遍历期间执行许多不同类型的操作,方法是根据元素的动态类型和元素的动态类型提供不同类型的访问者与元素进行交互来访者。

这可以在 Java car 示例中看到:

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

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

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

  1. 该模式的最初动机是:访问对象的复杂结构并对它们执行操作,而不改变被访问的类接口。
  2. 模式是如何实现的:正如你提到的那样,它是双重调度。

我强烈推荐以下设计模式书,因为它确实简化了许多概念。GoF 的书有时过于学术。

头部优先设计模式

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

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

专业人士

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

缺点

  • 当使用访问者时,复合类的封装被破坏。
  • 因为涉及到遍历函数,所以修改Composite结构比较困难
于 2012-07-30T13:31:04.717 回答
0

它非常简单(但可能有点混乱),访问者模式的重点是将访问者与被访问的事物分离。

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

布雷迪说了同样的话,我只是想少说几句

于 2012-07-30T14:00:33.727 回答