Краткий ответ: Я не вижу проблем с выставлением IVisitor, возвращающего универсальный параметр.
См. Правила FxCop .
Затем разрешается использовать разные IVisitor , каждый из которых возвращает свое значение.
Однако, в вашем случае , Посетитель не полезен, так как каждое животное имеет свойство Возраст , поэтому все можно сделать с помощью Животное или с новым IAnimal интерфейс.
В качестве альтернативы используется многократная отправка за счет потери Строгий набор .
Используйте шаблон Visitor , если вы хотите заменить (или не писать) переключатель следующим образом:
IAnimal animal = ...;
switch (animal.GetType().Name)
{
case "Peacock":
var peacock = animal as Peacock;
// Do something using the specific methods/properties of Peacock
break;
case "Lion":
var peacock = animal as Lion;
// Do something using the specific methods/properties of Lion
break;
etc...
}
или вложенный if-then-else эквивалент.
Его цель - направить экземпляр к подпрограмме, соответствующей его типу, используя полиморфизм, а затем избегать некрасивых операторов if-then-else / switch и ручные броски . Кроме того, это помогает уменьшить связь между несвязанным кодом.
Альтернативой этому является добавление виртуального метода в дерево классов для посещения. Однако иногда это невозможно или нежелательно:
- код посещаемого класса не модифицируется (например, не принадлежит)
- код посещаемого класса не относится к коду посещения (добавление его в класс будет означать снижение сцепления класса).
Именно поэтому он часто используется для обхода дерева объектов (html-узлы, лексерные токены и т. Д.). Шаблон Visitor подразумевает следующие интерфейсы:
IVisitor
/// <summary>
/// Interface to implement for classes visiting others.
/// See Visitor design pattern for more details.
/// </summary>
/// <typeparam name="TVisited">The type of the visited.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
public interface IVisitor<TVisited, TResult> : IVisitor where TVisited : IVisitable
{
TResult Visit(TVisited visited);
}
/// <summary>
/// Marking interface.
/// </summary>
public interface IVisitor{}
IVisitable
/// <summary>
/// Interface to implement for classes visitable by a visitor.
/// See Visitor design pattern for more details.
/// </summary>
/// <typeparam name="TVisitor">The type of the visitor.</typeparam>
/// <typeparam name="TResult">The type of the result.</typeparam>
public interface IVisitable<TVisitor, TResult> : IVisitable where TVisitor : IVisitor
{
TResult Accept(TVisitor visitor);
}
/// <summary>
/// Marking interface.
/// </summary>
public interface IVisitable {}
Реализация Принять в каждом IVisitable должен вызывать Визит (это) .