访客模式:访客或访问对象是否应该决定访问顺序?

时间:2014-11-29 21:16:06

标签: design-patterns visitor

我已经看过两种方式的例子,特别是维基百科显示了访问对象决定访问顺序的一个例子,我认为这是一种听起来的方法。

我处于这种情况,我需要几个访问订单,所以让访客决定访问订单似乎是合理的。但是,如果访问者负责访问顺序(即,用于调用被访问对象的accept方法),我可以让访问者直接调用一些访问方法(即绕过调用访问对象的accept方法)和这似乎与模式提出的完全相反。

实施访问模式的正确方法是什么,以及当我们有多个不同的访问订单时如何处理?

3 个答案:

答案 0 :(得分:4)

我相信没有"一种正确的方式"。正确的方式是满足您需求的方式。

访问者必须访问对象结构的每个元素。问题是,它是如何实现的?谁负责遍历对象结构? GoF设计模式书的答案如下:

  

1-通常,对象结构负责迭代。一个   集合将简单地遍历其元素,调用Accept   每个人的操作。

     

2-另一种解决方案是使用迭代器来访问元素。

     

3- 您甚至可以将遍历算法放入访问者中   您将最终复制每个ConcreteVisitor中的遍历代码   对于每个聚合ConcreteElement。放的主要原因   访客的遍历策略是特别实施的   复杂的遍历,取决于操作的结果   关于对象结构。

所以让访客决定访问订单是可以的。

答案 1 :(得分:2)

好问题。您似乎将设计模式视为食谱甚至算法,而它们实际上只是一种讨论程序员一直在做的事情的方式。没有正确的方法来实现模式。

在访问者模式的情况下,在访问对象上调用accept的点是每个访问对象可能具有不同的内部结构。在这种情况下(例如,程序的语法树),从访问者隐藏此内部结构是有意义的。在其他情况下,访问数据的结构是同质的,例如XML文档,它对于访问者决定订单非常有意义。

如果访问过的对象具有不同的内部结构,但您希望以不同的顺序访问它们,则可以使用不同的accept方法(acceptPreOrderacceptPostOrder)来访问例如,节点,然后是它的孩子或孩子,然后是节点。为了简单起见,您还可以使用一个接受order参数的accept方法。这也是有问题的,因为访问对象需要实现所有可能的遍历顺序。如果访问者对访问对象的结构有足够的了解来决定遍历顺序,那么让访问者直接处理访问给定对象的子代可能会更好。

答案 2 :(得分:0)

对于大多数语言,请确定访问者中的所有内容。 accept()的唯一目的是调度访问对象的运行时类型。这是一个简洁的解决方案,除了不能访问没有接受的内置类型如number / bool / null和closed / finalized类型。如果您需要处理这些情况,那么您最终会在访问者,访问对象和客户端代码中分发类型反射意大利面条代码。通过删除accept()简化类型反射和分派。处理所有类型并在访问者中统一发送,包括例外。现在,没有接受,很明显在哪里放置您的访问逻辑。创建一个处理类型和异常的基本访问者,然后扩展它以处理访问顺序,然后再次扩展它以使实际访问者。

如果您对访问对象有特殊的导航需求,则该访问对象(或其类)可以公开从上面的一般访问者派生的特殊目的访问者。例如,当一般访问处理程序访问Foo时,它可以从foo和fooVisitor.visit(foo.child)获取FooVisitor。通过这种方式你可以处理例如Foo的String或Array子元素与处理Bar的String或Array子元素的方式不同。考虑使用那个糟糕的accept()方法会有多乱。你必须接受一个上下文...说接受“是的,你是一个字符串,但你是foo中的一个字符串”。现在我们接受(上下文),这太可怕了。