2015-12-01 7 views
2

Я нашел много людей реализовать посетитель шаблон проектирования в питоне следующим образом:Является ли accept() необходимым при реализации шаблона проектирования посетителей в python?

class Node(object): 
    def accept(self, visitor): 
     visitor.visit(self) 
    # some code ... 
class Visitor(object): 
    def visit(self, node): 
     # invoke corresponding method according to the type of node 
     # ... 

node = Node() 
visitor = Vistor() 
node.accept(visitor) 

Для Java или другого C-подобного статического языка, они используют accept() для реализации мульти-отправки. Поскольку метод visit() выбирает конкретный метод переопределения только статическим типом ссылки. Например:

public class MyVisitor implements IVisitor { 
    void visit(AddNode node); 
    void visit(Node node); 
} 
Node node = AddNode(); // AddNode is derived from Node 
new MyVisitor().visit(root); 

Посетитель будет вызывать метод Node, а не AddNode. Таким образом, accept() необходимо, чтобы получить «реальный» тип, например следующим образом:

public class AddNode extends Node implements IVisitable{ 
    void accept(IVisitor visitor) { 
     visitor.visit(this) 
    } 
} 

Однако тип можно непосредственно извлечь из экземпляра в Python. Visitor можно осуществить следующим образом:

class Visitor(object): 
    def visit(self, node): 
     classname = node.__class__.__name__ 
     _visit = getattr(self, '_visit_'+classname) 
     _visit(node) 
    def _visit_AddNode(self, node): 
     pass 

Тогда мы могли бы посетить узел с помощью visit() непосредственно

node = AddNode() 
visitor = Visitor() 
visitor.visit(node) 

Этот способ является более естественным и простым. Почему люди все еще используют шаблон дизайна Visitor в python с accept()?

ответ

0

Ну, я не думаю, что мой ответ будет решить вопрос полностью, но в любом случае:

  1. при удалении accept метода из узлов вы проверить это перестает быть реализация шаблона Visitor (как это ясно см. at the diagram);

  2. способ, которым вы написали код, работает только для языков, поддерживающих интроспекцию, таким образом, чтобы динамически получить класс экземпляра (type introspection). У нас есть инструменты для этого в Python, но на других языках, которые могут быть не так просто реализовать/приятно читать.

Есть еще одна тема, посвященная проблеме stackoverflow: «What is the point of accept() method in Visitor pattern?». Здесь вы найдете много интересных деталей, например. когда узел является сложной составной структурой и, таким образом, делегирует вызов метода accept своим частям.