访客模式,为什么有用?

时间:2018-06-14 09:31:00

标签: python design-patterns visitor

我使用了here给出的访客示例我们在哪里:

.------------------------.
|        Flower          |
+------------------------+ 
| +accept(visitor)       |
| +pollinate(pollinator) |
| +eat(eater)            |
'------------------------'

我们还有一个Bug和一个Bee可以pollinate一个FlowerPredator可以eat一朵花。

使用vistor模式我可以这样写:

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

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

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

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

问题是,在这个例子中,访客模式有哪些优势?

1 个答案:

答案 0 :(得分:2)

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

  

假设您有一个固定的主类层次结构;也许它来自其他供应商,您无法对该层次结构进行更改。但是,您的意图是您希望向该层次结构添加新的多态方法,这意味着通常您必须向基类接口添加一些内容。所以困境是你需要向基类添加方法,但是你不能触及基类。你怎么解决这个问题?

当然,如果你只需要为蜜蜂,苍蝇和蠕虫添加visit方法,那就没关系了。但当你不能时,使用访客模式是下一个最好的选择。

请注意,文章中的关系是相反的;你不能改变Flower层次结构:

# The Flower hierarchy cannot be changed:

但是通过visit方法支持访问者调度模式:

class Flower(object):
    def accept(self, visitor):
        visitor.visit(self)

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

例如,可能有复合类,其中包含多个子组件。然后,accept()方法将进一步委托给那些子元素,然后根据需要在它们上面调用accept。保持花卉主题,也许有一个Chrysanthemum or Dahlia class,一些游客会吃光线组件,而其他人则想要参观眼睛中的组件进行授粉。由复合对象决定将每个访问者分别指向这些部分。

如果您正在寻找具体的示例,请查看ast module,其中提供NodeVisitor class应该进行子类化以添加方法,以便您自定义传入的AST树的处理方式。我使用了特定的NodeTransformer subclass来改变Python代码在several occasions上的工作方式。这里访问者模式用于有效地过滤掉更大层次结构中的某些类型,大大简化了AST处理代码,而不必自己更改任何AST节点类。