2014-11-29 2 views
4

Я видел примеры в обоих направлениях, в частности, в Википедии показан пример, где посетивший объект решает порядок посещения, и я думаю, что это звуковой подход.Шаблон посетителя: должен ли посетитель или посетивший объект принять решение о посещении?

Я нахожусь в ситуации, когда мне понадобится несколько распоряжений о посещении, поэтому представляется разумным разрешить посетителю принять решение о посещении. Однако, если посетитель несет ответственность за заказ на посещение (т. Е. Для вызова метода accept для объекта, который вы посещаете), я мог бы заставить посетителя напрямую вызвать какой-либо метод посещения (т. Е. Обойти вызов метода принятия объекта посещения) и это кажется совершенно противоположным тому, что предлагает шаблон.

Каков правильный способ реализации шаблона посещения и как действовать, когда у нас есть несколько разных заказов на посещение?

ответ

3

Я считаю, что нет «одного правильного пути». Правильный путь - это способ, который отвечает вашим потребностям.

Посетитель должен посетить каждый элемент структуры объекта. Вопрос в том, как он туда добирается? Кто отвечает за перемещение структуры объекта? Книга шаблонов моделей GoF отвечает на вопрос следующим образом:

1 - Часто структура объекта отвечает за итерацию. Коллекция будет просто перебирать элементы, вызывающие операцию Accept .

2- Еще одно решение - использовать итератор для посещения элементов.

3- Можно даже поставить алгоритм обхода в посетитель, хотя вы в конечном итоге дублирования кода обхода в каждом ConcreteVisitor для каждого агрегатного ConcreteElement. Основная причина для размещения стратегии обхода у посетителя заключается в реализации комплексного обхода , который зависит от результатов операций от структуры объекта.

Так что это нормально, если посетитель примет решение о посещении.

+0

Спасибо, я собирался заглянуть в GoF. Мой второй пункт все еще остается. Что хорошего в методе «принять» объект, если метод «посещения» одного посетителя может сразу вызвать другие методы «посещения»? – JohnTortugo

+1

Шаблоны помогают вам общаться с другими разработчиками. Когда я вижу ваш код, я могу заметить шаблон посетителя и ожидать, что вы вызовете метод accept. Если вы вызываете что-то еще, я становлюсь подозрительным и начинаю думать, если это из-за чего-то, чего я не понимаю. Это цель метода accept. Если вы кодируете API для других, чтобы использовать и хотите, чтобы клиенты не вызывали другие методы, добавьте еще один уровень абстракции. Если это частный код, просто не вызывайте другие методы. –

1

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

В случае шаблона посетителя точка вызова accept на посещенном объекте состоит в том, что каждый посетивший объект может иметь другую внутреннюю структуру. В таком случае (например, дерево синтаксиса программы) имеет смысл скрыть эту внутреннюю структуру от посетителя. В других случаях структура посещенных данных является однородной, такой как XML-документ, для покупателя имеет смысл определить порядок.

В тех случаях, когда посещаемые объекты различной внутренней структурой, но вы хотите посетить их в различных заказов, вы можете иметь различные accept методы (acceptPreOrder и acceptPostOrder) посетить, например, узел, а затем это дети или дети а затем узел. Чтобы все было просто, вы также можете использовать один метод accept, который принимает параметр order. Это также проблематично, потому что посещаемые объекты должны реализовывать все возможные порядки обхода. Если посетитель достаточно узнает о структуре посещенных объектов, чтобы принять решение об обходном порядке, на самом деле может быть лучше разрешить посетителю обращаться непосредственно к дочерним объектам данного объекта.

+0

Спасибо за ответ. Моим первым выстрелом были разные методы приема разных посетителей. Во-вторых, нужно было иметь перегруженный метод приема для посетителей, выполняющих разные заказы на посещение. Тем не менее, я ищу хорошую мягкость. инженерные консультации. Я не думаю, что рассматриваю шаблоны, поскольку они были алгоритмами: если бы мы могли свободно менять шаблон, это не было бы образцом. – JohnTortugo

0

Для большинства языков выберите все в посетителе. Единственной целью accept() является отправка в тип среды выполнения объекта. Это аккуратное решение, за исключением того, что встроенные типы, такие как number/bool/null и закрытые/финализированные типы без принятия, не могут быть посещены. Если вам нужно обрабатывать эти случаи, вы завершаете код спагетти с отражением типа, распределенный по вашим посетителям, посетившим объектам и клиентскому коду. Упростите отражение и отправку типа, удалив accept(). Обращайтесь со всеми типами и отправляйте равномерно посетителю, включая исключения. Теперь, не принимая, очевидно, где поставить свою логику посещения. Сделайте базового посетителя, который обрабатывает типы и исключения, затем расширьте это, чтобы обрабатывать порядок посещений, а затем расширьте это снова, чтобы сделать фактических посетителей.

Если у вас есть особые потребности в навигации для посещенного объекта, то тот посетивший объект (или его класс) может выставить посетителя специального назначения, который получен от общего посетителя выше. Например, когда общий обработчик посещений посещает Foo, он может получить FooVisitor из foo и fooVisitor.visit (foo.child). Таким образом, вы можете обрабатывать, например, String или Array child из Foo иначе, чем вы будете обрабатывать дочерний элемент String или Array. Подумайте, как бесполезно это использовать с помощью этого ужасного метода accept(). Вы должны дать принять контекст ... сказать, чтобы принять «да, вы строка, но вы строка в foo». Теперь мы принимаем (контекст), и это просто ужасно.