为什么有人要使用访问者模式?我已经阅读了几篇文章,但我没有得到任何东西。
如果我需要一个功能来为自定义计费,我可以使用
Custom.Accept(BillVisitor)
或类似的东西
Bill(Customer)
第二个不太复杂,Bill 函数仍然与 Customer 类分开。那么我为什么要使用访问者模式呢?
为什么有人要使用访问者模式?我已经阅读了几篇文章,但我没有得到任何东西。
如果我需要一个功能来为自定义计费,我可以使用
Custom.Accept(BillVisitor)
或类似的东西
Bill(Customer)
第二个不太复杂,Bill 函数仍然与 Customer 类分开。那么我为什么要使用访问者模式呢?
当您具有复杂的结构(即层次结构或其他不是简单线性的东西)时,就会出现问题。当您不能简单地迭代结构时,访问者非常方便。
如果我有一个层次结构(或树),每个节点都有一个子节点列表。当我想对树中的每个节点应用一个进程时,创建一个访问者是很愉快的。
然后一个节点可以将访问者应用到它自己,以及它的每个子节点。每个孩子,可传递地,做同样的事情(将访问者应用于它自己,然后是任何孩子)。
访问者的这种使用效果非常好。
当你有一个超级简单的数据结构时,Visitor 不会增加很多价值。
访问者模式是针对不直接支持多分派的语言的 hack(C++ 和 Java 等语言仅支持基于对象的单分派。CLOS 支持多分派)。在这种情况下,如果您希望 Bill 和 Customer 都是多态的,您将不得不使用单一调度语言中的 BillVisitor 和 Customer 两个接口。例如:accept的实现通常是:
void accept(BillVisitor visitor) { visitor.bill(this); } // java syntax
请注意,Customer#accept 和 BillVisitor#bill 都可以被它们各自的子类覆盖,从而产生非常丰富的运行时行为组合,否则无法实现。它实际上是大多数其他人在此描述的替代闭包的超集,可将功能应用于复杂的数据结构。
访问者的另一个好处是它们易于扩展,如果您的语言允许,您甚至可以使用 lamdbas 来清理内容。
在我的 CAD/CAM 应用程序中,我有路径和路径集合 (PathList)。有时我必须生成一组形状。我不仅要生成这个特定的形状集合,我还必须将它包含在另一个形状集合中。我经常需要十几个或更多参数来传达进行计算所需的所有信息。
我的 CAM 中的所有形状计算(简单或复杂)都汇集到一个 PathList 中,该路径列表被发送到不同的机器。
使用这种设计,最好进行一些设置,包括将结果添加到单个集合中。
Path Visitor 非常适合这一点。每个形状计算都被封装到它自己的类中,其属性根据需要而复杂。
所以 Kitchen Hood Visitor 可能有 8 个形状到路径列表
而厨房柜台访客增加了 6 个形状。
抽屉访客增加了一些。
然后我像任何其他形状生成器一样将生成的 PathList 传递给系统的其余部分。
通过添加另一个访问者或不运行一些访问者,我可以轻松地进行选择。对于一个只想要一个柜台和抽屉的人来说,我只需要运行两个访客。
生成的代码非常可读,当我在 3、5 或 10 年后重新访问该领域时,这一点很重要。此外,由于对一个访问者的封装更改对其他访问者的影响很小。
此外,我现在有一个标准化的设计模式,可以通过实现访问者模式向 PathList 添加任何新功能。
例如,过去我们的属性编辑器只能在单个路径上工作。当我们改为编辑多个路径时,很容易实现自定义访问者对所有路径进行全局更改。它比在委托中使用 for 循环更具可读性。
但最终归结为判断和偏好。
在这两种情况下,访问者都与客户类分开。如果您也想从调用者类中抽象出访问者,那么优势将是。在第二种情况下,调用类必须知道计费。相反,您可以在某个地方使用另一个例程来返回 IVisitor。然后调用代码可以调用 Custom.Accept(IVisitor) 并且不知道访问者在做什么。
基本上在这种情况下以及 S.Lott 提到的情况下,您可以将访问者视为代表。这是一个可以像对象一样传递并在需要时使用的函数。