Посетитель (Visitor)
Паттерн Посетитель используется для расширения возможностей комбинации объектов в том случае, если инкапсуляция не существенна.
-
Visitor - абстрактный посетитель
-
ConcreteVisitor - конкртеный посетитель
-
Element - абстрактный элемент
-
ConcreteElement - конкретный элемент
-
ObjectStructure - структура объектов
Абстрактная реализация на C# (GoF)
/// <summary>
/// MainApp startup class for Structural
/// Visitor Design Pattern.
/// </summary>
internal class MainApp
{
private 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>
internal abstract class Visitor
{
public abstract void VisitConcreteElementA(
ConcreteElementA concreteElementA);
public abstract void VisitConcreteElementB(
ConcreteElementB concreteElementB);
}
/// <summary>
/// A 'ConcreteVisitor' class
/// </summary>
internal 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>
internal 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>
internal abstract class Element
{
public abstract void Accept(Visitor visitor);
}
/// <summary>
/// A 'ConcreteElement' class
/// </summary>
internal class ConcreteElementA : Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitConcreteElementA(this);
}
public void OperationA()
{
}
}
/// <summary>
/// A 'ConcreteElement' class
/// </summary>
internal class ConcreteElementB : Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitConcreteElementB(this);
}
public void OperationB()
{
}
}
/// <summary>
/// The 'ObjectStructure' class
/// </summary>
internal 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);
}
}
}
Реальная реализация на C# (GoF)
/// <summary>
/// MainApp startup class for Real-World
/// Visitor Design Pattern.
/// </summary>
internal class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
private static void Main()
{
// Setup employee collection
Employees employee = new Employees();
employee.Attach(new Clerk());
employee.Attach(new Director());
employee.Attach(new President());
// Employees are 'visited'
employee.Accept(new IncomeVisitor());
employee.Accept(new VacationVisitor());
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Visitor' interface
/// </summary>
internal interface IVisitor
{
void Visit(Element element);
}
/// <summary>
/// A 'ConcreteVisitor' class
/// </summary>
internal class IncomeVisitor : IVisitor
{
public void Visit(Element element)
{
Employee employee = element as Employee;
// Provide 10% pay raise
employee.Income *= 1.10;
Console.WriteLine("{0} {1}'s new income: {2:C}",
employee.GetType().Name, employee.Name,
employee.Income);
}
}
/// <summary>
/// A 'ConcreteVisitor' class
/// </summary>
internal class VacationVisitor : IVisitor
{
public void Visit(Element element)
{
Employee employee = element as Employee;
// Provide 3 extra vacation days
Console.WriteLine("{0} {1}'s new vacation days: {2}",
employee.GetType().Name, employee.Name,
employee.VacationDays);
}
}
/// <summary>
/// The 'Element' abstract class
/// </summary>
internal abstract class Element
{
public abstract void Accept(IVisitor visitor);
}
/// <summary>
/// The 'ConcreteElement' class
/// </summary>
internal class Employee : Element
{
private string name;
private double income;
private int vacationDays;
// Constructor
public Employee(string name, double income,
int vacationDays)
{
this.name = name;
this.income = income;
this.vacationDays = vacationDays;
}
// Gets or sets the name
public string Name
{
get { return name; }
set { name = value; }
}
// Gets or sets income
public double Income
{
get { return income; }
set { income = value; }
}
// Gets or sets number of vacation days
public int VacationDays
{
get { return vacationDays; }
set { vacationDays = value; }
}
public override void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
/// <summary>
/// The 'ObjectStructure' class
/// </summary>
internal class Employees
{
private List<Employee> employees = new List<Employee>();
public void Attach(Employee employee)
{
employees.Add(employee);
}
public void Detach(Employee employee)
{
employees.Remove(employee);
}
public void Accept(IVisitor visitor)
{
foreach (Employee employee in employees)
{
employee.Accept(visitor);
}
Console.WriteLine();
}
}
// Three employee types
internal class Clerk : Employee
{
// Constructor
public Clerk()
: base("Hank", 25000.0, 14)
{
}
}
internal class Director : Employee
{
// Constructor
public Director()
: base("Elly", 35000.0, 16)
{
}
}
internal class President : Employee
{
// Constructor
public President()
: base("Dick", 45000.0, 21)
{
}
}
Улучшенная реальная реализация на C# (GoF)
/// <summary>
/// MainApp startup class for .NET optimized
/// Visitor Design Pattern.
/// </summary>
internal class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
private static void Main()
{
// Setup employee collection
var employee = new Employees();
employee.Attach(new Clerk());
employee.Attach(new Director());
employee.Attach(new President());
// Employees are 'visited'
employee.Accept(new IncomeVisitor());
employee.Accept(new VacationVisitor());
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Visitor' abstract class
/// </summary>
public abstract class Visitor
{
// Use reflection to see if the Visitor has a method
// named Visit with the appropriate parameter type
// (i.e. a specific Employee). If so, invoke it.
public void ReflectiveVisit(IElement element)
{
var types = new Type[] { element.GetType() };
var mi = this.GetType().GetMethod("Visit", types);
if (mi != null)
{
mi.Invoke(this, new object[] { element });
}
}
}
/// <summary>
/// A 'ConcreteVisitor' class
/// </summary>
internal class IncomeVisitor : Visitor
{
// Visit clerk
public void Visit(Clerk clerk)
{
DoVisit(clerk);
}
// Visit director
public void Visit(Director director)
{
DoVisit(director);
}
private void DoVisit(IElement element)
{
var employee = element as Employee;
// Provide 10% pay raise
employee.Income *= 1.10;
Console.WriteLine("{0} {1}'s new income: {2:C}",
employee.GetType().Name, employee.Name,
employee.Income);
}
}
/// <summary>
/// A 'ConcreteVisitor' class
/// </summary>
internal class VacationVisitor : Visitor
{
// Visit director
public void Visit(Director director)
{
DoVisit(director);
}
private void DoVisit(IElement element)
{
var employee = element as Employee;
// Provide 3 extra vacation days
employee.VacationDays += 3;
Console.WriteLine("{0} {1}'s new vacation days: {2}",
employee.GetType().Name, employee.Name,
employee.VacationDays);
}
}
/// <summary>
/// The 'Element' interface
/// </summary>
public interface IElement
{
void Accept(Visitor visitor);
}
/// <summary>
/// The 'ConcreteElement' class
/// </summary>
internal class Employee : IElement
{
// Constructor
public Employee(string name, double income,
int vacationDays)
{
this.Name = name;
this.Income = income;
this.VacationDays = vacationDays;
}
// Gets or sets name
public string Name { get; set; }
// Gets or set income
public double Income { get; set; }
// Gets or sets vacation days
public int VacationDays { get; set; }
public virtual void Accept(Visitor visitor)
{
visitor.ReflectiveVisit(this);
}
}
/// <summary>
/// The 'ObjectStructure' class
/// </summary>
internal class Employees : List<Employee>
{
public void Attach(Employee employee)
{
Add(employee);
}
public void Detach(Employee employee)
{
Remove(employee);
}
public void Accept(Visitor visitor)
{
// Iterate over all employees and accept visitor
this.ForEach(employee => employee.Accept(visitor));
Console.WriteLine();
}
}
// Three employee types
internal class Clerk : Employee
{
// Constructor
public Clerk()
: base("Hank", 25000.0, 14)
{
}
}
internal class Director : Employee
{
// Constructor
public Director()
: base("Elly", 35000.0, 16)
{
}
}
internal class President : Employee
{
// Constructor
public President()
: base("Dick", 45000.0, 21)
{
}
}
Реализация на JAVA
TODO