Существует обширное исследование по этому вопросу в проекте кода - Шаблон посетителя повторно объяснен .
Я предоставлю заголовок.
Шаблон посетителя здесь, чтобы решить вещи, представив два аспекта:
- Существует итерационный механизм, который знает, как перебирать объекты.
hirerachy.it ничего не знает о поведении объектов в
иерархия.
- Новое поведение, которое необходимо реализовать, ничего не знает о
механизм итерации, они не знают, как перебрать объект
иерархия.
Теперь Оба этих аспектов не зависят друг от друга, и их не следует смешивать друг с другом. Итак, это все о принципале ООП, известном как принципал единой ответственности , возвращающий вас к ТВЕРДОМУ архитектуре .
Ключевые игроки в этой функции:
- Посетитель - Интерфейс, который определяет операцию посещения. Это
ядро шаблона посетителя. Он определяет операцию посещения для каждого типа
бетонного элемента в структуре объекта.
- ConcreateVisitor - Реализует операции, определенные в Visitor
интерфейс.
- ElementBase : Это абстрактный / интерфейс, который определяет Accept
операция, которая принимает посетителя в качестве аргумента.
- ConcreateElement - В этих типах реализован метод принятия элемента.
интерфейс.
- Структура объекта - Содержит все элементы структуры данных как
коллекция, список или что-то, что может быть перечислено и использовано
гости. Это обеспечивает интерфейс для всех посетителей, чтобы посетить его
элемент. Эти элементы включают в себя метод под названием «Принять».
коллекция затем перечисляется
Теперь цель всего этого шаблона, ключа , состоит в том, чтобы создать модель данных с ограниченными функциональными возможностями и набор посетителей с определенными функциональными возможностями, которые будут работать с данными. Шаблон позволяет посетителю посетить каждый элемент структуры данных, передавая объект в качестве аргумента методам посетителя.
Преимущества в конце концов-
Ключ отделения алгоритма от его модели данных - это возможность легко добавлять новые поведения. Классы модели данных создаются с помощью общего метода Visit, который может принимать объект посетителя во время выполнения. Затем можно создать другой объект посетителя и передать его этому методу, затем этот метод вызвал обратный вызов метода посетителя, передав ему себя в качестве параметра.
Стоит упомянуть еще одну вещь: :
Добавление нового типа в иерархию объектов требует изменений для всех посетителей, и это следует рассматривать как преимущество, поскольку оно определенно заставляет нас добавлять новый тип во все места, где вы сохранили некоторый код, специфичный для типа. По сути, это не просто позволяет забыть об этом.
Шаблон посетителя полезен только:
- Если интерфейс, который вы хотите реализовать, довольно статичен и не
изменить много.
- Если все типы известны заранее, то есть во время проектирования все объекты
должен быть известен.
В нижней строке:
Посетитель реализует следующие принципы проектирования :
- Разделение интересов - Шаблон посетителя продвигает этот принцип,
несколько аспектов / проблем разделены на несколько других классов, как
это способствует более чистому коду и повторному использованию кода, а также коду
более проверяемый.
- Принцип единой ответственности - образец посетителя также обеспечивает это
принцип. Объект должен иметь почти одну ответственность. несвязанный
поведение должно быть отделено от него другим классом.
- Принцип Открытого Закрытия - шаблон посетителя также следует этому принципу,
как будто мы хотим расширить поведение объекта, исходный код
не изменен. Шаблон Visitor предоставляет нам механизм для
separaэто другой класс и применить эти операции для объекта
во время выполнения.
Преимущества реализации Visitor: :
- Отделите поведение структуры данных от них. Отдельные посетители
Объект создан для реализации такого поведения.
- Это решает проблему Double Dispatch, с которой редко сталкиваются, но имеет
важное влияние.
Вы можете углубиться в статью, чтобы понять весь смысл этого, но если я приведу пример:
Прежде всего мы определим интерфейс, который мы называем IVisitable. Он определит единственный метод Accept, который будет принимать аргумент IVisitor. Этот интерфейс будет служить основой для всех типов в списке продуктов. Все типы, такие как Book, Car и Wine (в нашем примере) будут реализовывать этот тип.
/// <summary>
/// Define Visitable Interface.This is to enforce Visit method for all items in product.
/// </summary>
internal interface IVisitable
{
void Accept(IVisitor visit);
}
Тогда мы это осуществим:
#region "Structure Implementations"
/// <summary>
/// Define base class for all items in products to share some common state or behaviors.
/// Thic class implement IVisitable,so it allows products to be Visitable.
/// </summary>
internal abstract class Product : IVisitable
{
public int Price { get; set; }
public abstract void Accept(IVisitor visit);
}
/// <summary>
/// Define Book Class which is of Product type.
/// </summary>
internal class Book : Product
{
// Book specific data
public Book(int price)
{
this.Price = price;
}
public override void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
/// <summary>
/// Define Car Class which is of Product type.
/// </summary>
internal class Car : Product
{
// Car specific data
public Car(int price)
{
this.Price = price;
}
public override void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
/// <summary>
/// Define Wine Class which is of Product type.
/// </summary>
internal class Wine : Product
{
// Wine specific data
public Wine(int price)
{
this.Price = price;
}
public override void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
#endregion "Structure Implementations"
Создайте интерфейс посетителя и внедрите его:
/// <summary>
/// Define basic Visitor Interface.
/// </summary>
internal interface IVisitor
{
void Visit(Book book);
void Visit(Car car);
void Visit(Wine wine);
}
#region "Visitor Implementation"
/// <summary>
/// Define Visitor of Basic Tax Calculator.
/// </summary>
internal class BasicPriceVisitor : IVisitor
{
public int taxToPay { get; private set; }
public int totalPrice { get; private set; }
public void Visit(Book book)
{
var calculatedTax = (book.Price * 10) / 100;
totalPrice += book.Price + calculatedTax;
taxToPay += calculatedTax;
}
public void Visit(Car car)
{
var calculatedTax = (car.Price * 30) / 100;
totalPrice += car.Price + calculatedTax;
taxToPay += calculatedTax;
}
public void Visit(Wine wine)
{
var calculatedTax = (wine.Price * 32) / 100;
totalPrice += wine.Price + calculatedTax;
taxToPay += calculatedTax;
}
}
#endregion "Visitor Implementation"
Исполнение:
static void Main(string[] args)
{
Program.ShowHeader("Visitor Pattern");
List<Product> products = new List<Product>
{
new Book(200),new Book(205),new Book(303),new Wine(706)
};
ShowTitle("Basic Price calculation");
BasicPriceVisitor pricevisitor = new BasicPriceVisitor();
products.ForEach(x =>
{
x.Accept(pricevisitor);
});
Console.WriteLine("");
}