`
阿尔萨斯
  • 浏览: 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

*/
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics