Для насколько я видел до сих пор существует два варианта использования/выгоды для шаблона дизайна посетитель:
- Double диспетчерский
- Отдельные структуры данных от операций по ним
Двойная отправка
Предположим, у вас есть класс Vehicle и класс VehicleWasher. VehicleWasher имеет метод Wash (Vehicle):
VehicleWasher
Wash(Vehicle)
Vehicle
Кроме того, мы также имеем специальные транспортные средства, как автомобиль, так и в будущем мы будем также иметь другие специальные транспортные средства. Для этого у нас есть класс автомобилей, но и определенный класс CarWasher, который имеет работу, специфичную для стиральных машин (псевдо код):
CarWasher : VehicleWasher
Wash(Car)
Car : Vehicle
Тогда рассмотрит следующий код клиента постирать конкретное транспортное средство (обратите внимание, что х и шайбу объявляются с использованием их базового типа, так как экземпляры могут быть динамически создается на основе пользовательского ввода или внешних конфигурационных значений, в данном примере они просто созданы с новым оператором, хотя):
Vehicle x = new Car();
VehicleWasher washer = new CarWasher();
washer.Wash(x);
Многие языки используют единую отправку для вызова соответствующая функция. Единая отправка означает, что во время выполнения только одно значение учитывается при определении способа вызова. Поэтому мы будем рассматривать только настоящий тип шайбы. Фактический тип x не учитывается. Поэтому последняя строка кода будет ссылаться на CarWasher.Wash (Vehicle) и NOT CarWasher.Wash (Car).
Если вы используете язык, который не поддерживает множественную отправку, и вам это нужно (я могу с полным основанием сказать, что я никогда не сталкивался с такой ситуацией), тогда вы можете использовать шаблон дизайна посетителя, чтобы включить это. Для этого нужно сделать две вещи. Прежде всего добавить метод Accept к классу транспортных средств (далее посещаемый), который принимает VehicleWasher в качестве гостя, а затем вызвать его работу Wash:
Accept(VehicleWasher washer)
washer.Wash(this);
Второй вещь, чтобы изменить код вызова и заменить шайбу. Мытье (х); линия со следующим:
x.Accept(washer);
Теперь для вызова метода Accept фактического типа х считается (и только то, что х, так как мы предполагаем, чтобы использовать единый язык отправки). При реализации метода Accept метод Wash вызывается на объекте шайбы (посетителя). Для этого рассматривается фактический тип шайбы, и это вызовет CarWasher.Wash (Car). Объединив два отдельных отправления, выполняется двойная отправка.
Теперь, чтобы рассказать о своем замечании таких терминов, как Accept and Visit и Visitor, очень неспецифические. Это абсолютно верно. Но это по какой-то причине.
В этом примере рассмотрите требование о внедрении нового класса, способного ремонтировать транспортные средства: автомобильRepairer. Этот класс можно использовать только в качестве посетителя в этом примере, если он наследует от VehicleWasher и имеет свою логику восстановления внутри метода Wash. Но это, конечно, не имеет никакого смысла и будет путать.Поэтому я полностью согласен с тем, что шаблоны проектирования имеют тенденцию иметь очень неопределенное и неспецифическое наименование, но это делает их применимыми ко многим ситуациям. Чем конкретнее ваше именование, тем более ограничительным может быть.
В вашем заявлении о коммутаторе учитывается только один тип, который на самом деле является ручным способом отправки. Применение шаблона дизайна посетителя вышеописанным способом обеспечит двойную отправку. Таким образом, при добавлении дополнительных типов в вашу иерархию необязательные дополнительные методы посещения. Конечно, это добавляет некоторую сложность, поскольку делает код менее удобочитаемым. Но, конечно, все шаблоны приходят по цене.
Конечно, этот шаблон не всегда может быть использован. Если вы ожидаете множество сложных операций с несколькими параметрами, это не будет хорошим вариантом.
Альтернативой является использование языка, который поддерживает множественную отправку. Например, .NET не поддерживал его до версии 4.0, которая ввела динамическое ключевое слово. Тогда в C# вы можете сделать следующее:
washer.Wash((dynamic)x);
Поскольку х затем преобразуется в динамический тип его фактический тип будет рассматриваться для отправки и поэтому будут использоваться оба х и стеклоомыватели, чтобы выбрать правильный метод так, чтобы CarWasher.Wash (Car) будет вызван (что сделает код корректным и останется интуитивным).
Отдельные структуры данных и операции
Другая выгода и требование заключается в том, что он может отделить от структуры данных операций. Это может быть преимуществом, поскольку оно позволяет добавлять новых посетителей, которые имеют собственные операции, а также позволяют добавлять структуры данных, которые «наследуют» эти операции. Однако он может применяться только в том случае, если это разделение может быть сделано/имеет смысл. Классы, которые выполняют операции (посетители), не знают структуру структур данных и не должны знать, что делает код более удобным и многоразовым. При применении по этой причине посетители имеют операции для разных элементов в структурах данных.
Скажем, у вас разные структуры данных, и все они состоят из элементов класса Item. Структуры могут быть списки, стеки, деревья, очереди и т.д.
Вы можете реализовать посетителей, что в этом случае будет иметь следующий метод:
Visit(Item)
Структуры данных должны принимать посетителей, а затем вызвать Метод посещения для каждого элемента.
Таким образом вы можете реализовать все виды посетителей, и вы можете добавлять новые структуры данных, если они состоят из элементов типа Item.
Для более конкретных структур данных с дополнительными элементами (например, узла) вы можете рассмотреть конкретного посетителя (NodeVisitor), который наследуется от вашего обычного посетителя, и ваши новые структуры данных принимают этого посетителя (Accept (NodeVisitor)). Новые посетители могут использоваться для новых структур данных, а также для старых структур данных из-за наследования, и поэтому вам не нужно изменять существующий «интерфейс» (в этом случае суперкласс).
ИМО вы пропустили важный момент ... вы должны ** НИКОГДА ** (I будет писать еще больше) имеют что-то вроде 'switch (type of obj)'. Не имеет значения, посетитель или нет. Если ваш код не такой, вы не будете писать код шаблона. –
** Примеры **, когда посетитель может вам помочь? Представьте, что нужно писать утилиту для поиска текста внутри файлов. Поисковая система будет посещать каждый элемент файловой системы (файлы будут посещаться, а каталоги будут распространять посещение каждого дочернего элемента). Элементы файловой системы могут быть каталогами, файлами, ссылками на FTP-сайты ... поисковая система никогда не узнает, с чем это работает. Посетитель не должен знать точный тип (не из-за шаблона посетителя, а из-за принципов ООП ...) –
Посетители - это слишком низкий уровень. Нет смысла использовать посетителей, когда вы можете сделать что-то вроде этого: http://www.cs.indiana.edu/~dyb/pubs/nano-jfp.pdf –