Я использовал приведенный здесь пример посетителя. Где у нас есть:
.------------------------.
| 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)
Вопрос в том, какие преимущества предоставляют шаблон посетителя в этом примере?
В статье, на которой вы ссылаетесь, довольно ясно, почему вы хотите использовать шаблон посетителя: когда вы не можете изменять объекты, потому что они происходят от третьего лица:
Предполагается, что у вас установлена иерархия первичного класса; возможно, от другого поставщика, и вы не можете внести изменения в эту иерархию. Однако ваше намерение заключается в том, что youd хотел бы добавить новые полиморфные методы в эту иерархию, а это означает, что обычно вам нужно добавить что-то в интерфейс базового класса. Поэтому дилемма заключается в том, что вам нужно добавить методы в базовый класс, но вы не можете прикоснуться к базовому классу. Как вам обойти это?
Конечно, если вы можете просто добавить метод visit
пчел, мух и червей, то это прекрасно. Но когда вы не можете, использование шаблона посетителя является следующим лучшим вариантом.
Заметим, что в статье соотношение обратное; вы не можете изменить иерархию Flower
:
# The Flower hierarchy cannot be changed:
но класс поддерживает шаблон отправки посетителя через метод visit
:
class Flower(object):
def accept(self, visitor):
visitor.visit(self)
Эта реализация может быть намного сложнее; пример был упрощен до простого visitor.visit()
здесь, но на практике реальный шаблон посетителя может и делает гораздо больше на этом этапе.
Например, могут быть составные классы, которые содержат несколько подкомпонентов. Метод accept()
затем будет делегировать далее эти подэлементы, чтобы затем при необходимости accept
их на всех. Сохраняясь с цветочной темой, возможно, есть класс хризантемы или Далии, где некоторые посетители будут есть компоненты луча, в то время как другие хотели бы посетить компоненты в глазу, чтобы опылять. Это до составного объекта, чтобы направить каждого посетителя на эти части по отдельности.
Если вы ищете конкретные примеры, посмотрите на модуль ast
, который предлагает класс NodeVisitor
который должен быть подклассифицирован, чтобы добавить методы, позволяющие вам настроить, как обрабатывается дерево AST. Я использовал конкретный подкласс NodeTransformer
чтобы изменить способ работы кода Python несколько раз. Здесь шаблон посетителя используется для эффективного фильтрации определенных типов в более крупной иерархии, что значительно упрощает код обработки АСТ без необходимости изменять какой-либо из классов узлов АСТ.
accept()
всегда будет простой отправкой. Обновлено.