访客模式 - 添加新的 ConcreteElement 类很难



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

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

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

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

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

为什么?

好吧,假设调用方是"工厂",并且您有元素"汽车"和"自行车"。

对于操作"油漆",您必须具有方法

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

同样,对于"组装","包装","洗涤"等操作。

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

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

这是一些工作。此外,您可能会遇到 isse,您添加的元素与其他元素如此不同,以至于您无法轻松地将它们放入操作中。

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

从本质上讲,访问者允许人们向 类族而不修改类本身;相反 一个创建一个 visitor 类来实现所有适当的 虚拟功能的专业化。访客采取 实例引用作为输入,并通过双倍实现目标 遣。

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

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

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

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

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

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

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

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

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

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

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

如果将访问者的所有访问方法分离到访问函子中,并将它们动态绑定在一起,那么在扩展 how 系统时,对于访问者和访问者来说,可能会更容易。

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

https://github.com/tezheng/visitor

最新更新