访问者模式介绍
封装一些作用于某种数据结构中的各元素的操作
它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
- 参与者
参与此模式的类和对象是:
- Visitor 访问客(Visitor 访问客)
为对象结构中的每个ConcreteElement类声明了一个Visit操作。 操作的名称和签名标识向访问者发送Visit请求的类。 这让访问者可以确定被访问元素的具体类。 然后,访问者可以通过其特定的接口直接访问这些元素
- ConcreteVisitor 具体访问者 (IncomeVisitor, VacationVisitor)
实现Visitor声明的每个操作。 每个操作实现为结构中相应的类或对象定义的算法片段。 ConcreteVisitor为算法提供上下文并存储其本地状态。 这种状态经常在结构遍历期间累积结果。
- Element 元素(Element 元素)
定义了一个接受visitor作为参数的Accept操作。
- ConcreteElement 具体元素 (Employee 员工)
实现一个Accept操作,该操作将访问者作为参数
- ObjectStructure 对象工厂 (Employees 员工)
可以枚举它的元素
可能提供一个高级接口,允许访问者访问它的元素
可以是一个Composite(模式),也可以是一个集合,如列表或集合
访问者模式
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class VisitorStructure : MonoBehaviour
{
void Start ( )
{
// 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
// v1 访问 o中的所有元素
// eleA eleB 均接受访问 各自执行 访问者 A/B类型的访问方法
// v1 访问 A 会执行v1 的 visitA方法
// v1 访问 B 会执行v1 的 visitB方法
o.Accept(v1);
o.Accept(v2);
}
}
/// <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)
{
Debug.Log(concreteElementA.GetType().Name+" visited by "+this.GetType().Name);
}
public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
{
Debug.Log(concreteElementB.GetType().Name + " visited by " + this.GetType().Name);
}
}
/// <summary>
/// A 'ConcreteVisitor' class
/// </summary>
class ConcreteVisitor2 : Visitor
{
public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
{
Debug.Log(concreteElementA.GetType().Name + " visited by " + this.GetType().Name);
}
public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
{
Debug.Log(concreteElementB.GetType().Name + " visited by " + 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);
}
}
}
访问者模式案例1
//这段真实的代码演示了Visitor模式,其中两个对象遍历一个Employee列表,并对每个Employee执行相同的操作。
//两个访问者对象定义不同的操作——一个调整休假天数,另一个调整收入。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace VisitorPatternExample1
{
public class VisitorPatternExample1 : MonoBehaviour
{
void Start()
{
// Setup employee collection
Employees e = new Employees();
e.Attach(new Clerk());
e.Attach(new Director());
e.Attach(new President());
// Employees are 'visited'
e.Accept(new IncomeVisitor());
e.Accept(new VacationVisitor());
}
}
/// <summary>
/// The 'Visitor' interface
/// </summary>
interface IVisitor
{
void Visit(Element element);
}
/// <summary>
/// A 'ConcreteVisitor' class
/// </summary>
class IncomeVisitor : IVisitor
{
public void Visit(Element element)
{
Employee employee = element as Employee;
// Provide 10% pay raise
employee.Income *= 1.10;
Debug.Log(employee.GetType().Name+" "+ employee.Name+"'s new income: "+employee.Income);
}
}
/// <summary>
/// A 'ConcreteVisitor' class
/// </summary>
class VacationVisitor : IVisitor
{
public void Visit(Element element)
{
Employee employee = element as Employee;
// Provide 3 extra vacation days
employee.VacationDays += 3;
Debug.Log(employee.GetType().Name + " " + employee.Name + "'s new vacation days:" + employee.VacationDays);
}
}
/// <summary>
/// The 'Element' abstract class
/// </summary>
abstract class Element
{
public abstract void Accept(IVisitor visitor);
}
/// <summary>
/// The 'ConcreteElement' class
/// </summary>
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>
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 e in _employees)
{
e.Accept(visitor);
}
}
}
// Three employee types
class Clerk : Employee
{
// Constructor
public Clerk()
: base("Hank", 25000.0, 14)
{
}
}
class Director : Employee
{
// Constructor
public Director()
: base("Elly", 35000.0, 16)
{
}
}
class President : Employee
{
// Constructor
public President()
: base("Dick", 45000.0, 21)
{
}
}
}
访问者模式案例2
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace VisitorPatternExample2
{
public class VisitorPatternExample2 : MonoBehaviour
{
void Start()
{
// Setup employee collection
Employees e = new Employees();
e.Attach(new Clerk());
e.Attach(new Director());
e.Attach(new President());
// Employees are 'visited'
e.Accept(new IncomeVisitor());
e.Accept(new VacationVisitor());
}
/// <summary>
/// The 'Visitor' interface
/// </summary>
interface IVisitor
{
void Visit(Element element);
}
/// <summary>
/// A 'ConcreteVisitor' class
/// </summary>
class IncomeVisitor : IVisitor
{
public void Visit(Element element)
{
Employee employee = element as Employee;
// Provide 10% pay raise
employee.Income *= 1.10;
Debug.Log(string.Format("{0} {1}'s new income: {2:C}",
employee.GetType().Name, employee.Name,
employee.Income));
}
}
/// <summary>
/// A 'ConcreteVisitor' class
/// </summary>
class VacationVisitor : IVisitor
{
public void Visit(Element element)
{
Employee employee = element as Employee;
// Provide 3 extra vacation days
employee.VacationDays += 3;
Debug.Log(string.Format("{0} {1}'s new vacation days: {2}",
employee.GetType().Name, employee.Name,
employee.VacationDays));
}
}
/// <summary>
/// The 'Element' abstract class
/// </summary>
abstract class Element
{
public abstract void Accept(IVisitor visitor);
}
/// <summary>
/// The 'ConcreteElement' class
/// </summary>
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>
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 e in _employees)
{
e.Accept(visitor);
}
}
}
// Three employee types
class Clerk : Employee
{
// Constructor
public Clerk()
: base("Hank", 25000.0, 14)
{
}
}
class Director : Employee
{
// Constructor
public Director()
: base("Elly", 35000.0, 16)
{
}
}
class President : Employee
{
// Constructor
public President()
: base("Dick", 45000.0, 21)
{
}
}
}
}