- 浏览: 4179649 次
最新评论
Design Pattern - Visitor (C#)
Definition
Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
UML Class Diagram
Participants
The classes and/or objects participating in this pattern are:
-
Visitor(Visitor)
- Declares a Visit operation for each class of ConcreteElement in the object structure. The operation's name and signature identifies the class that sends the Visit request to the visitor. That lets the visitor determine the concrete class of the element being visited. Then the visitor can access the elements directly through its particular interface.
-
ConcreteVisitor(IncomeVisitor, VacationVisitor)
- Implements each operation declared by Visitor. Each operation implements a fragment of the algorithm defined for the corresponding class or object in the structure. ConcreteVisitor provides the context for the algorithm and stores its local state. This state often accumulates results during the traversal of the structure.
-
Element(Element)
- Defines an Accept operation that takes a visitor as an argument.
-
ConcreteElement(Employee)
- Implements an Accept operation that takes a visitor as an argument.
-
ObjectStructure(Employees)
- Can enumerate its elements
- May provide a high-level interface to allow the visitor to visit its elements
- May either be a Composite (pattern) or a collection such as a list or a set
Sample Code in C#
This structural code demonstrates the Visitor pattern in which an object traverses an object structure and performs the same operation on each node in this structure. Different visitor objects define different operations.
// -------------------------------------------------------------------------------------------------------------------- // <copyright company="Chimomo's Company" file="Program.cs"> // Respect the work. // </copyright> // <summary> // Visitor pattern - Structural example // </summary> // -------------------------------------------------------------------------------------------------------------------- namespace CSharpLearning { using System; using System.Collections.Generic; /// <summary> /// Startup class for Structural Visitor Design Pattern. /// </summary> public static class Program { /// <summary> /// The main. /// </summary> public 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); } } /// <summary> /// The 'Visitor' abstract class /// </summary> public abstract class Visitor { /// <summary> /// Visit concrete element a. /// </summary> /// <param name="concreteElementA"> /// The concrete element a. /// </param> public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA); /// <summary> /// Visit concrete element b. /// </summary> /// <param name="concreteElementB"> /// The concrete element b. /// </param> public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB); } /// <summary> /// A 'ConcreteVisitor' class /// </summary> public class ConcreteVisitor1 : Visitor { /// <summary> /// Visit concrete element a. /// </summary> /// <param name="concreteElementA"> /// The concrete element a. /// </param> public override void VisitConcreteElementA(ConcreteElementA concreteElementA) { Console.WriteLine("{0} visited by {1}", concreteElementA.GetType().Name, this.GetType().Name); } /// <summary> /// Visit concrete element b. /// </summary> /// <param name="concreteElementB"> /// The concrete element b. /// </param> public override void VisitConcreteElementB(ConcreteElementB concreteElementB) { Console.WriteLine("{0} visited by {1}", concreteElementB.GetType().Name, this.GetType().Name); } } /// <summary> /// A 'ConcreteVisitor' class /// </summary> public class ConcreteVisitor2 : Visitor { /// <summary> /// Visit concrete element a. /// </summary> /// <param name="concreteElementA"> /// The concrete element a. /// </param> public override void VisitConcreteElementA(ConcreteElementA concreteElementA) { Console.WriteLine("{0} visited by {1}", concreteElementA.GetType().Name, this.GetType().Name); } /// <summary> /// Visit concrete element b. /// </summary> /// <param name="concreteElementB"> /// The concrete element b. /// </param> public override void VisitConcreteElementB(ConcreteElementB concreteElementB) { Console.WriteLine("{0} visited by {1}", concreteElementB.GetType().Name, this.GetType().Name); } } /// <summary> /// The 'Element' abstract class /// </summary> public abstract class Element { /// <summary> /// The accept. /// </summary> /// <param name="visitor"> /// The visitor. /// </param> public abstract void Accept(Visitor visitor); } /// <summary> /// A 'ConcreteElement' class /// </summary> public class ConcreteElementA : Element { /// <summary> /// The accept. /// </summary> /// <param name="visitor"> /// The visitor. /// </param> public override void Accept(Visitor visitor) { visitor.VisitConcreteElementA(this); } } /// <summary> /// A 'ConcreteElement' class /// </summary> public class ConcreteElementB : Element { /// <summary> /// The accept. /// </summary> /// <param name="visitor"> /// The visitor. /// </param> public override void Accept(Visitor visitor) { visitor.VisitConcreteElementB(this); } } /// <summary> /// The 'ObjectStructure' class /// </summary> public class ObjectStructure { /// <summary> /// The elements. /// </summary> private readonly List<Element> elements = new List<Element>(); /// <summary> /// The attach. /// </summary> /// <param name="element"> /// The element. /// </param> public void Attach(Element element) { this.elements.Add(element); } /// <summary> /// The accept. /// </summary> /// <param name="visitor"> /// The visitor. /// </param> public void Accept(Visitor visitor) { foreach (Element element in this.elements) { element.Accept(visitor); } } } } // Output: /* ConcreteElementA visited by ConcreteVisitor1 ConcreteElementB visited by ConcreteVisitor1 ConcreteElementA visited by ConcreteVisitor2 ConcreteElementB visited by ConcreteVisitor2 */
This real-world code demonstrates the Visitor pattern in which two objects traverse a list of Employees and performs the same operation on each Employee. The two visitor objects define different operations -- one adjusts vacation days and the other income.
// -------------------------------------------------------------------------------------------------------------------- // <copyright company="Chimomo's Company" file="Program.cs"> // Respect the work. // </copyright> // <summary> // Real-World Visitor Design Pattern. // </summary> // -------------------------------------------------------------------------------------------------------------------- namespace CSharpLearning { using System; using System.Collections.Generic; /// <summary> /// The 'Visitor' interface /// </summary> public interface IVisitor { #region Public Methods and Operators /// <summary> /// The visit. /// </summary> /// <param name="element"> /// The element. /// </param> void Visit(Element element); #endregion } /// <summary> /// The 'Element' abstract class /// </summary> public abstract class Element { #region Public Methods and Operators /// <summary> /// The accept. /// </summary> /// <param name="visitor"> /// The visitor. /// </param> public abstract void Accept(IVisitor visitor); #endregion } /// <summary> /// Startup class for Real-World Visitor Design Pattern. /// </summary> internal static class Program { #region Methods /// <summary> /// Entry point into console application. /// </summary> private static void Main() { // Setup employee collection var 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()); } #endregion } /// <summary> /// A 'ConcreteVisitor' class /// </summary> internal class IncomeVisitor : IVisitor { #region Public Methods and Operators /// <summary> /// The visit. /// </summary> /// <param name="element"> /// The element. /// </param> public void Visit(Element 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); } #endregion } /// <summary> /// A 'ConcreteVisitor' class /// </summary> internal class VacationVisitor : IVisitor { #region Public Methods and Operators /// <summary> /// The visit. /// </summary> /// <param name="element"> /// The element. /// </param> public void Visit(Element 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); } #endregion } /// <summary> /// The 'ConcreteElement' class /// </summary> internal class Employee : Element { // Constructor #region Constructors and Destructors /// <summary> /// Initializes a new instance of the <see cref="Employee"/> class. /// </summary> /// <param name="name"> /// The name. /// </param> /// <param name="income"> /// The income. /// </param> /// <param name="vacationDays"> /// The vacation days. /// </param> public Employee(string name, double income, int vacationDays) { this.Name = name; this.Income = income; this.VacationDays = vacationDays; } #endregion // Gets or sets income #region Public Properties /// <summary> /// Gets or sets the income. /// </summary> public double Income { get; set; } /// <summary> /// Gets or sets the name. /// </summary> public string Name { get; set; } /// <summary> /// Gets or sets the vacation days. /// </summary> public int VacationDays { get; set; } #endregion #region Public Methods and Operators /// <summary> /// The accept. /// </summary> /// <param name="visitor"> /// The visitor. /// </param> public override void Accept(IVisitor visitor) { visitor.Visit(this); } #endregion } /// <summary> /// The 'ObjectStructure' class /// </summary> internal class Employees { #region Fields /// <summary> /// The _employees. /// </summary> private List<Employee> employees = new List<Employee>(); #endregion #region Public Methods and Operators /// <summary> /// The accept. /// </summary> /// <param name="visitor"> /// The visitor. /// </param> public void Accept(IVisitor visitor) { foreach (Employee e in this.employees) { e.Accept(visitor); } Console.WriteLine(); } /// <summary> /// The attach. /// </summary> /// <param name="employee"> /// The employee. /// </param> public void Attach(Employee employee) { this.employees.Add(employee); } /// <summary> /// The detach. /// </summary> /// <param name="employee"> /// The employee. /// </param> public void Detach(Employee employee) { this.employees.Remove(employee); } #endregion } // Three employee types /// <summary> /// The clerk. /// </summary> internal class Clerk : Employee { // Constructor #region Constructors and Destructors /// <summary> /// Initializes a new instance of the <see cref="Clerk"/> class. /// </summary> public Clerk() : base("Hank", 25000.0, 14) { } #endregion } /// <summary> /// The director. /// </summary> internal class Director : Employee { // Constructor #region Constructors and Destructors /// <summary> /// Initializes a new instance of the <see cref="Director"/> class. /// </summary> public Director() : base("Elly", 35000.0, 16) { } #endregion } /// <summary> /// The president. /// </summary> internal class President : Employee { // Constructor #region Constructors and Destructors /// <summary> /// Initializes a new instance of the <see cref="President"/> class. /// </summary> public President() : base("Dick", 45000.0, 21) { } #endregion } } // Output: /* Clerk Hank's new income: $27,500.00 Director Elly's new income: $38,500.00 President Dick's new income: $49,500.00 Clerk Hank's new vacation days: 17 Director Elly's new vacation days: 19 President Dick's new vacation days: 24 */
相关推荐
算法的封装与切换——策略模式(四) 模板方法模式-Template Method Pattern 模板方法模式深度解析(一) 模板方法模式深度解析(二) 模板方法模式深度解析(三) 访问者模式-Visitor Pattern 操作复杂对象结构——...
$ npm install eslint-visitor-keys 要求 10.0.0或更高版本。 :open_book: 用法 const evk = require ( "eslint-visitor-keys" ) evk.keys 类型: { [type: string]: string[] | undefined } { [type: string]: ...
设计模式(20)-Visitor Pattern 设计模式(19)-Observer Pattern 设计模式(18)-Command Pattern 设计模式(17)-Chain of Responsibility Pattern 设计模式(16)-Bridge Pattern 设计模式(15)-Facade ...
Laravel开发-visitor-log Laravel 4记录所有访客的包
Laravel开发-visitor 以数据库、页面点击量记录您的访问者,并为Laravel 5生成访问计数器
Laravel开发-visitor-log .zip
访客设计模式使用访问者模式的示例项目。
Recruit-Restaurant-Visitor-Forecasting-master.zip
执行docker run -it -p 8080:8080 --rm --name running-best-visitor-server best-visitor-server 如何调试项目 docker run -it -p 8080:8080 --...
Reflect on the Visitor design pattern 访问者模式非常不错的讲解,很细致。
23种设计模式(Design Pattern)的C++实现范例,包括下面列出的各种模式,代码包含较详细注释。另外附上“设计模式迷你手册.chm”供参考。 注:项目在 VS2008 下使用。 创建型: 抽象工厂模式(Abstract Factory) 生成...
快速树访问者访问者模式 设计一个开发以下两个访问者的访问者:一个访问者,它读取输入文件input.txt,并用文件中的所有单词填充树数据结构。 使用树数据结构将第二位访问者的性能最大化。 使用该树数据结构的插入...
C#设计模式之1 --- Visitor (附原码)
Visitor.rarVisitor.rarVisitor.rarVisitor.rar访问者观察模式
Design Pattern: Simple Factory 模式 Design Pattern: Abstract Factory 模式 Design Pattern: Builder 模式 Design Pattern: Factory Method 模式 Design Pattern: Prototype 模式 Design Pattern: Singleton...
mahouka-fearful-visitor
可以看到,要实现操作权转让到 Visitor,核心是元素必须实现一个 Accept 函数,将这个对象抛给 Visitor:从上面代码可以看出这样一条链路:Ele