我使用了here给出的访客示例我们在哪里:
.------------------------.
| Flower |
+------------------------+
| +accept(visitor) |
| +pollinate(pollinator) |
| +eat(eater) |
'------------------------'
我们还有一个Bug
和一个Bee
可以pollinate
一个Flower
,Predator
可以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)
问题是,在这个例子中,访客模式有哪些优势?
答案 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节点类。