访客模式,为什么有用?

now*_*wox 3 python design-patterns visitor-pattern

我使用了这里给出的访客示例,我们有这个:

.------------------------.
|        Flower          |
+------------------------+ 
| +accept(visitor)       |
| +pollinate(pollinator) |
| +eat(eater)            |
'------------------------'
Run Code Online (Sandbox Code Playgroud)

我们还有可以是 a 的aBug和a ,以及可以是一朵花的 a 。BeepollinateFlowerPredatoreat

使用访问者模式我可以这样写:

bee = Bee()
fly = Fly()
worm = Worm()

# Using the visitor pattern:
for flower in flowerGen(10):    
    for object in [bee, fly, worm]:
        flower.accept(object)
Run Code Online (Sandbox Code Playgroud)

但代码在没有访问者的情况下仍然具有可读性和功能性:

# Without visitor pattern 
for flower in flowerGen(10):
    for object in [bee, fly, worm]:
        object.visit(flower)
Run Code Online (Sandbox Code Playgroud)

问题是,此示例中的访问者模式有哪些优点?

Mar*_*ers 5

您链接到的文章非常清楚地说明了为什么您想要使用访问者模式:当您无法更改对象时,因为它们来自第三方

\n\n
\n

假设您有一个固定的主类层次结构;也许它来自另一个供应商,您可以\xe2\x80\x99t 更改该层次结构。但是,您的意图是您\xe2\x80\x99d 喜欢向该层次结构添加新的多态方法,这意味着通常您\xe2\x80\x99d 必须向基类接口添加一些内容。所以困境是你需要向基类添加方法,但你不能\xe2\x80\x99接触基类。你如何解决这个问题?

\n
\n\n

当然,如果您可以为蜜蜂、苍蝇和蠕虫添加一种visit方法,那就没问题了。但是,当您不能时,使用访问者模式是下一个最佳选择。

\n\n

请注意,在文章中,关系是相反的;您无法更改Flower层次结构:

\n\n
\n
# The Flower hierarchy cannot be changed:\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

但该类确实通过以下方法支持访问者调度模式visit

\n\n
class Flower(object):\n    def accept(self, visitor):\n        visitor.visit(self)\n
Run Code Online (Sandbox Code Playgroud)\n\n

该实施可能要复杂得多;该示例已被简化为此处的visitor.visit()一个简单调用,但实际上,真正的访问者模式在此阶段可以并且确实可以执行更多操作。

\n\n

例如,可能存在包含多个子组件的复合类。然后,该accept()方法将进一步委托给这些子元素,然后accept根据需要调用它们。与花卉主题保持一致,也许有菊花或大丽花类,一些游客会吃射线成分,而其他人则想访问眼睛中的成分来授粉。由复合对象将每个访问者单独引导至这些部分。

\n\n

如果您正在寻找特定的示例,请查看 module ast它提供了一个NodeVisitor,该类应该被子类化以添加方法,以便您自定义传入的 AST 树的处理方式。我曾多次使用特定的NodeTransformer子类来改变 Python 代码的工作方式。这里,访问者模式用于有效地过滤掉较大层次结构中的某些类型,从而极大地简化了 AST 处理代码,而无需更改任何 AST 节点类本身。

\n