Паттерн «Посетитель» (Visitor)
Categories:
💻 Programming
Назначение: описывает операцию, выполняемую с каждым объектом из некоторой иерархии классов. Паттерн «Посетитель» позволяет определить новую операцию, не изменяя классов этих объектов.
Когда использовать паттерн Посетитель
- Паттерн Посетитель определяет операцию, выполняемую на каждом элементе из некоторой структуры. Позволяет, не изменяя классы этих объектов, добавлять в них новые операции.
- Является классической техникой для восстановления потерянной информации о типе.
- Паттерн Посетитель позволяет выполнить нужные действия в зависимости от типов двух объектов.
- Предоставляет механизм двойной диспетчеризации.
UML схема паттерна Visitor
Реализация шаблона "посетитель" на C#
using System;
using System.Collections.Generic;
namespace DoFactory.GangOfFour.Visitor.Structural
{
/// <summary>
/// MainApp startup class for Structural
/// Visitor Design Pattern.
/// </summary>
class MainApp
{
static void Main()
{
// Setup structure
ObjectStructure o = new ObjectStructure();
o.Attach(new ConcreteElementA());
o.Attach(new ConcreteElementB());
// Create visitor objects
ConcreteVisitor1 v1 = new ConcreteVisitor1();
ConcreteVisitor2 v2 = new ConcreteVisitor2();
// Structure accepting visitors
o.Accept(v1);
o.Accept(v2);
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Visitor' abstract class
/// </summary>
abstract class Visitor
{
public abstract void VisitConcreteElementA(
ConcreteElementA concreteElementA);
public abstract void VisitConcreteElementB(
ConcreteElementB concreteElementB);
}
/// <summary>
/// A 'ConcreteVisitor' class
/// </summary>
class ConcreteVisitor1 : Visitor
{
public override void VisitConcreteElementA(
ConcreteElementA concreteElementA)
{
Console.WriteLine("{0} visited by {1}",
concreteElementA.GetType().Name, this.GetType().Name);
}
public override void VisitConcreteElementB(
ConcreteElementB concreteElementB)
{
Console.WriteLine("{0} visited by {1}",
concreteElementB.GetType().Name, this.GetType().Name);
}
}
/// <summary>
/// A 'ConcreteVisitor' class
/// </summary>
class ConcreteVisitor2 : Visitor
{
public override void VisitConcreteElementA(
ConcreteElementA concreteElementA)
{
Console.WriteLine("{0} visited by {1}",
concreteElementA.GetType().Name, this.GetType().Name);
}
public override void VisitConcreteElementB(
ConcreteElementB concreteElementB)
{
Console.WriteLine("{0} visited by {1}",
concreteElementB.GetType().Name, this.GetType().Name);
}
}
/// <summary>
/// The 'Element' abstract class
/// </summary>
abstract class Element
{
public abstract void Accept(Visitor visitor);
}
/// <summary>
/// A 'ConcreteElement' class
/// </summary>
class ConcreteElementA : Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitConcreteElementA(this);
}
public void OperationA()
{
}
}
/// <summary>
/// A 'ConcreteElement' class
/// </summary>
class ConcreteElementB : Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitConcreteElementB(this);
}
public void OperationB()
{
}
}
/// <summary>
/// The 'ObjectStructure' class
/// </summary>
class ObjectStructure
{
private List<Element> _elements = new List<Element>();
public void Attach(Element element)
{
_elements.Add(element);
}
public void Detach(Element element)
{
_elements.Remove(element);
}
public void Accept(Visitor visitor)
{
foreach (Element element in _elements)
{
element.Accept(visitor);
}
}
}
}
Схема примера использования паттерна "Посетитель" из реальной жизни:
Примеры в .NET Framework
- ExpressionTreeVisitor используется для работы с деревьями выражений (Expression Trees) в .NET Framework. Данный посетитель используется для навигации и преобразования деревьев выражений при реализации специализированных LINQ-провайдеров, а также для решения других задач.
- Roslyn содержит множество посетителей. CSharpSyntaxVisitor предназначен для работы с синтаксическим деревом, SymbolVisitor<TResult> — для работы с символами и др.
- DbExpressionVisitor используется в Entity Framework для SQL-выражений.
Comments:
Please log in
to be able add comments.
👍