Подтвердить что ты не робот

Зачем использовать шаблон посетителя?

Дубликат: Когда следует использовать шаблон дизайна посетителя

Почему кто-то хочет использовать шаблон посетителя? Я прочитал пару статей, но я ничего не получаю.

Если мне нужна функция для выставления счета, я мог бы использовать

Custom.Accept(BillVisitor)

или что-то вроде

Bill(Customer)

Второй вариант менее сложный, и функция Билла все еще отделена от класса Customer. Так почему я хотел бы использовать шаблон посетителя?

4b9b3361

Ответ 1

Проблема возникает, когда у вас сложная структура, т.е. иерархия или что-то еще, что не просто линейно. Когда вы не можете просто перебирать структуру, посетителю очень удобно.

Если у меня есть иерархия (или дерево), каждый Node имеет список детей. Когда я хочу применить процесс к каждому Node в дереве, приятно создать посетителя.

A Node может затем применить посетителя к себе и к каждому из его дочерних узлов. Каждый ребенок, транзитивно, делает то же самое (примените посетителя к себе, а затем к любым детям).

Это использование посетителя очень хорошо работает.

Когда у вас есть суперпростая структура данных, Visitor не добавляет большого значения.

Ответ 2

Шаблон посетителя - это взлом для языков, которые не поддерживают множественную отправку напрямую (язык, такой как С++, и Java поддерживает только одну отправку на основе объекта. Несколько диспетчеров поддерживаются CLOS). В этом случае, если вы хотите, чтобы и Bill, и Customer были полиморфными, вам придется использовать два интерфейса, BillVisitor и Customer на отдельных языках рассылки. Например: реализация accept обычно:

void accept(BillVisitor visitor) { visitor.bill(this); } // java syntax

Обратите внимание, что как счетчик # accept, так и счет BillVisitor # могут быть переопределены их соответствующими подклассами, что приводит к очень богатой комбинации поведения во время выполнения, чего нельзя добиться иначе. Это действительно надмножество того, что большинство других людей описано здесь как замена закрытия, чтобы применить функциональность к сложным структурам данных.

Ответ 3

В моем приложении CAD/CAM у меня есть Paths и Collections of Paths (PathList). Иногда мне приходится создавать коллекцию фигур. Я не только должен генерировать эту конкретную коллекцию форм, я должен включить ее в другую коллекцию фигур. Мне часто требуется дюжина или более параметров для передачи всей информации, необходимой для проведения расчетов.

Все вычисления формы (простые или сложные) в моем CAM направляют PathList, который отправляется на разные машины.

В этом дизайне лучше всего иметь некоторую настройку, которая включает в себя добавление результата в одну коллекцию.

The Path Visitor отлично подходит для этого. Каждое вычисление формы инкапсулируется в собственный класс с такими сложными свойствами, как необходимые.

Таким образом, посетитель кухонной вытяжки может иметь 8 фигур для Pathlist

В то время как посетитель кухонного счетчика добавляет 6 форм.

Ящик Visitor добавляет еще несколько.

Затем я передаю полученный PathList остальной системе, как любой другой генератор формы.

У меня легко есть варианты, добавляя другого посетителя или не запуская некоторые. Для парня, который хочет только счетчик и ящики, мне нужно всего лишь запустить двух посетителей.

Полученный код очень читабельен, что важно, когда я пересматриваю эту область на 3, 5 или 10 лет. Кроме того, из-за инкапсуляции изменения одного посетителя имеют минимальное влияние на других посетителей.

Кроме того, теперь у меня есть стандартизованный шаблон проектирования, чтобы добавить любую новую функциональность в PathList, реализовав шаблон посетителя.

Например, когда-то наш редактор свойств работал только по одному пути. Когда мы перешли на редактирование нескольких путей, было легко реализовать пользовательских посетителей для глобальных изменений ко всем путям. Это было более читаемым, а затем использовалось для циклов внутри делегатов.

Но в конечном итоге это сводится к суждению и предпочтению.

Ответ 4

Еще один приятный сюрприз для посетителей - их легко расширить, и если ваш язык позволяет это, вы можете даже использовать lamdbas для очистки вещей.

Ответ 5

В обоих случаях посетитель отделен от класса клиента. Преимущество было бы, если бы вы хотели отвлечь посетителя от класса вызывающего. Во втором случае вызывающий класс должен знать о выставлении счетов. Вместо этого у вас может быть другая процедура, которая вернет IVisitor. Затем вызывающий код может вызвать Custom.Accept(IVisitor) и не знать ничего о том, что делает посетитель.

В основном в этом случае и в случае, о котором упомянул S.Lott, вы можете думать о посетителе, как о делегате. Это функция, которую вы можете передавать как объект и использовать там, где это необходимо.