0

我读了一本关于访客模式的书。它提供了与oodesign 网站中相同的类图。

它说添加新的 ConcreteElement 类很难。但我不明白为什么。据我了解,Concretevisitor 定义了具体元素必须使用的一组操作。因此,当我添加一个具有我之前定义的相同操作的新元素时,我不需要添加任何东西(只需 ConcreteElement 本身)。如果我添加一个新元素,它没有我之前在访问者中定义的相同操作,我需要添加一个新访问者。但这是我必须在任何设计模式中做的。

4

4 回答 4

3

好吧,您必须扩展所有访问者。

您有一个调用者,一些需要访问的元素,以及一个元素 - 访问者 - 对各个元素进行处理。您的目标是保持元素和调用者的实现固定,并通过新访问者扩展功能。

通常你有很多具体的访客。如果添加要处理的新元素类型,则需要更改所有具体访问者以考虑到这一点。

为什么?

好吧,假设调用者是“Factory”,并且您有元素“Car”和“Bike”。

对于“油漆”操作,您必须拥有方法

void process(Car c); // Paint a car
void process(Bike b); // Paint a bike

对于“组装”、“包装”、“清洗”等操作也是如此。

如果添加元素“Scooter”,则必须使用新方法扩展所有操作

void process(Scooter s); // Handle a Scooter

这有点工作。此外,您可能会遇到您添加的元素与其他元素如此不同的问题,以至于您无法轻松地将它们适合操作。

维基百科(http://en.wikipedia.org/wiki/Visitor_pattern)说

本质上,访问者允许在不修改类本身的情况下向类族中添加新的虚函数;相反,我们创建了一个访问者类,它实现了虚函数的所有适当的特化。访问者将实例引用作为输入,并通过双重调度实现目标。

这是一种非常抽象的方式来表达我上面试图说的内容。通常你会将这些方法添加到元素中,但如果你不能,你必须将这些方法添加到其他东西中,并将其传递给进行处理。这是一些额外的工作,但如果情况合适,这可能是值得的。

于 2012-06-28T11:12:32.827 回答
1

这是最近出现在一个 SO 问题中的。从这个问题引用我自己,更具体地说是讨论

不更改实体集(您访问的类)的前提条件是因为它迫使您在每个具体访问者中实现一个新的 VisitXYZ。但是我从来没有考虑过这种推理,因为如果你支持持久性访问者、文本搜索访问者、打印访问者和验证访问者,然后你去添加一个新实体,你将要实现所有这些反正功能。访问者模式(具有公共基类)只是让编译器找到您忘记为您实现的那些。

所以是的,人们常说很难实现添加具体元素(或实体),但在我看来,这是胡说八道。

于 2012-06-28T12:13:14.537 回答
1

如果您添加一个新的具体元素,那么您的所有访问者类都需要visit为新元素添加一个新方法。如果您不使用访问者,则无论如何都必须将等效方法添加到新的具体元素中。

但是为每个访问者添加一个新方法可能比向一个新元素类添加等效的方法集更难。原因是访问者经常需要遍历元素树结构,并且可能需要在这样做时管理自己的状态数据。添加新visit方法可能需要修改状态数据,这涉及考虑新方法如何与visit其他元素的现有方法交互。

如果您没有访问者,将等效方法添加到您的新元素类可能会更简单,因为您只需要担心更具凝聚力的新具体元素的内部状态。

于 2012-06-28T12:27:45.407 回答
1

从本质上讲,访问者模式是一种数据操纵器,它将

  • 遵循一些规则在元素之间遍历
  • 对这些元素提供的数据进行一些计算和操作

一言以蔽之,访问者模式将扩展系统功能,而无需触及元素类定义。

但这是否意味着如果添加了新的具体元素类,则必须修改访问者类?我相信,这取决于访问者模式的设计和实现方式。

如果将visitor的所有访问方法拆分成visit functors,并动态绑定在一起,那么在扩展how系统时,无论是visitor还是visitee,都可能会更容易一些。

这是我几年前写的访问者模式的实现,代码有点旧,没有很好的修饰,但不知何故可以工作:)

https://github.com/tezheng/visitor

于 2012-07-01T07:11:07.890 回答