我正在寻找“访客”模式的常见用例。我可以在Internet上找到一些示例,但它们只是基础,只能说明概念,而不能在这种模式真正节省您的时间/生命的情况下提供。
您是否有使用这种模式的真实示例? (例如,在Github中现有的Java项目中)
我不清楚它能大规模解决什么问题,为什么开发人员可以使用它?
答案 0 :(得分:2)
当您要向对象发送消息(即调用方法)时,访问者模式很有用,但是由于编译器的类型检查而不能。例如,该对象被声明为属于类型(接口)Animal
,它仅具有方法say()
,而您想对该对象调用方法smile()
。
是的,您可以修改接口Animal
(以添加方法smile()
),但是出于某种原因,您希望保持接口稳定。如果将来您需要更多的方法,例如go()
,walk()
...?
是的,您可以将Animal
对象转换为所需的每种特定类型,例如Dog
,Cat
...但是由于某些原因,您希望保持此代码稳定。将来如果您有更多的动物类型,例如Bird
,Elephant
...怎么办?
因此,让我们将所有这些不稳定的事情委托给访问者。您将拥有SmileVisitor
,GoVisitor
,WalkVisitor
...,方法为visit(Dog)
,visit(Cat)
...
P / S:我想您会发现一些常见的用例,可以自己保持源代码的某些部分稳定。
答案 1 :(得分:0)
四个人所表示的Visitor
模式的意图表示要在对象结构的元素上执行的操作。 Visitor
使您可以定义新操作,而无需更改要对其进行操作的元素的类[1]。
考虑一个将程序表示为抽象语法树的编译器。它将需要在抽象语法树上执行操作以进行“静态语义”分析,例如检查是否已定义所有变量。它还将需要生成代码。因此,它可以定义用于类型检查,代码优化,流程分析,在使用变量之前检查变量是否已分配值的操作,等等。此外,我们可以使用抽象语法树进行漂亮的打印,程序重组,代码检测以及计算程序的各种指标[1]。
这里的问题是,将所有这些操作分布在各个节点类上会导致系统难以理解,维护和更改。将类型检查代码与漂亮的打印代码或流分析代码混合在一起会造成混乱。此外,添加新操作通常需要重新编译所有这些类。如果可以分别添加每个新操作,并且节点类独立于适用于它们的操作,则更好[1]。
在此处查看我的博客以获取更多详细信息[2]
[2] https://medium.com/@ravindraranwala/visitor-design-pattern-e282dd1a5625
答案 2 :(得分:0)
大多数人都将GoF手册用作参考,但是对于这些学习模式而言,阅读起来并不容易(我知道,我尝试过!)。
无意打扰或矛盾拉文德拉·兰瓦拉,这是我对“访客”的英语描述及其目的。
让我们说您有一个“对象结构”,如树或其他任何东西,其元素是某些基类的子类-即实现一个公共接口。有上万亿个例子,遍历结构,随手使用元素的方法,这并不罕见。
典型的例子是由算术表达式解析器构造的解析树。构造树时,您可能会在head元素上调用Evaluate(),并且它将遍历树并递归地调用树中的Evaluate()以达到表达式的结果。
现在假设您想对树进行其他操作,但是不幸的是,元素没有支持您想做的事情的方法。输入Visitor,这需要向每个元素添加一个名为accept()的附加“可编程” 方法。
我们还需要一个单独的Visitor对象,每个对象要实现一个新的“算法”。每个Visitor对象必须为元素的每个子类实现一个visit(NodeType n)方法。意味着在每个节点上进行的新处理将取决于所访问节点的类型。
然后遍历树,在每个元素中调用accept(XVisitor vis)方法。接着,accept()方法调用vis-> visit(this),将对自身的引用传递回Visitor,该访问者最终为该节点类型调用visit()的正确版本。
因此,如果您的元素对象从一开始就设置为包括“可编程” accept()方法,那么您可以执行Visitor模式所承诺的操作-让您“定义新操作而无需更改元素上的类它可以运作”。
这实际上是一个简单的想法,但由于实现它的机制而感到困惑,当然,不同的语言也有不同的用法。因此,您必须为Java或PHP或其他任何东西仔细研究一下。
GoF中的示例是一个抽象的解析树,您稍后可能希望在其中进行一些其他处理或类型检查或其他任何事情,而这些并不是最初设计树时所设想的。访客允许稍稍“后门” 以后再做新的事情,而不会干扰元素对象或树。
希望这会有所帮助...