1. 程式人生 > >Chain of Responsibility(C#)

Chain of Responsibility(C#)

               

Definition

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

Participants

    The classes and/or objects participating in this pattern are:

  • Handler
     (Approver)
    • Defines an interface for handling the requests
    • (optional) Implements the successor link
  • ConcreteHandler (Director, VicePresident, President)
    • Handles requests it is responsible for
    • Can access its successor
    • If the ConcreteHandler can handle the request, it does so; otherwise it forwards the request to its successor
  • Client (ChainApp)
    • Initiates the request to a ConcreteHandler object on the chain

Sample Code in C#

This structural code demonstrates the Chain of Responsibility pattern in which several linked objects (the Chain) are offered the opportunity to respond to a request or hand it off to the object next in line.

// --------------------------------------------------------------------------------------------------------------------// <copyright company="Chimomo's Company" file="Program.cs">// Respect the work.// </copyright>// <summary>// Structural Chain of Responsibility Design Pattern.// </summary>// --------------------------------------------------------------------------------------------------------------------namespace CSharpLearning{    using System;    /// <summary>    /// Startup class for Structural Chain of Responsibility Design Pattern.    /// </summary>    internal static class Program    {        #region Methods        /// <summary>        /// Entry point into console application.        /// </summary>        private static void Main()        {            // Setup Chain of Responsibility            Handler h1 = new ConcreteHandler1();            Handler h2 = new ConcreteHandler2();            Handler h3 = new ConcreteHandler3();            h1.SetSuccessor(h2);            h2.SetSuccessor(h3);            // Generate and process request            int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };            foreach (int request in requests)            {                h1.HandleRequest(request);            }        }        #endregion    }    /// <summary>    /// The 'Handler' abstract class    /// </summary>    internal abstract class Handler    {        #region Fields        /// <summary>        /// The successor.        /// </summary>        protected Handler Successor;        #endregion        #region Public Methods and Operators        /// <summary>        /// The handle request.        /// </summary>        /// <param name="request">        /// The request.        /// </param>        public abstract void HandleRequest(int request);        /// <summary>        /// The set successor.        /// </summary>        /// <param name="successor">        /// The successor.        /// </param>        public void SetSuccessor(Handler successor)        {            this.Successor = successor;        }        #endregion    }    /// <summary>    /// The 'ConcreteHandler1' class    /// </summary>    internal class ConcreteHandler1 : Handler    {        #region Public Methods and Operators        /// <summary>        /// The handle request.        /// </summary>        /// <param name="request">        /// The request.        /// </param>        public override void HandleRequest(int request)        {            if (request >= 0 && request < 10)            {                Console.WriteLine("{0} handled request {1}", this.GetType().Name, request);            }            else if (this.Successor != null)            {                this.Successor.HandleRequest(request);            }        }        #endregion    }    /// <summary>    /// The 'ConcreteHandler2' class    /// </summary>    internal class ConcreteHandler2 : Handler    {        #region Public Methods and Operators        /// <summary>        /// The handle request.        /// </summary>        /// <param name="request">        /// The request.        /// </param>        public override void HandleRequest(int request)        {            if (request >= 10 && request < 20)            {                Console.WriteLine("{0} handled request {1}", this.GetType().Name, request);            }            else if (this.Successor != null)            {                this.Successor.HandleRequest(request);            }        }        #endregion    }    /// <summary>    /// The 'ConcreteHandler3' class    /// </summary>    internal class ConcreteHandler3 : Handler    {        #region Public Methods and Operators        /// <summary>        /// The handle request.        /// </summary>        /// <param name="request">        /// The request.        /// </param>        public override void HandleRequest(int request)        {            if (request >= 20 && request < 30)            {                Console.WriteLine("{0} handled request {1}", this.GetType().Name, request);            }            else if (this.Successor != null)            {                this.Successor.HandleRequest(request);            }        }        #endregion    }}// Output:/*ConcreteHandler1 handled request 2ConcreteHandler1 handled request 5ConcreteHandler2 handled request 14ConcreteHandler3 handled request 22ConcreteHandler2 handled request 18ConcreteHandler1 handled request 3ConcreteHandler3 handled request 27ConcreteHandler3 handled request 20*/
This real-world code demonstrates the Chain of Responsibility pattern in which several linked managers and executives can respond to a purchase request or hand it off to a superior. Each position has can its own set of rules which orders they can approve.
// --------------------------------------------------------------------------------------------------------------------// <copyright company="Chimomo's Company" file="Program.cs">// Respect the work.// </copyright>// <summary>// Real-World Chain of Responsibility Design Pattern.// </summary>// --------------------------------------------------------------------------------------------------------------------namespace CSharpLearning{    using System;    /// <summary>    /// Startup class for Real-World Chain of Responsibility Design Pattern.    /// </summary>    internal static class Program    {        #region Methods        /// <summary>        /// Entry point into console application.        /// </summary>        private static void Main()        {            // Setup Chain of Responsibility            Approver larry = new Director();            Approver sam = new VicePresident();            Approver tammy = new President();            larry.SetSuccessor(sam);            sam.SetSuccessor(tammy);            // Generate and process purchase requests            var p = new Purchase(2034, 350.00, "Assets");            larry.ProcessRequest(p);            p = new Purchase(2035, 32590.10, "Project X");            larry.ProcessRequest(p);            p = new Purchase(2036, 122100.00, "Project Y");            larry.ProcessRequest(p);        }        #endregion    }    /// <summary>    /// The 'Handler' abstract class    /// </summary>    internal abstract class Approver    {        #region Fields        /// <summary>        /// The successor.        /// </summary>        protected Approver Successor;        #endregion        #region Public Methods and Operators        /// <summary>        /// The process request.        /// </summary>        /// <param name="purchase">        /// The purchase.        /// </param>        public abstract void ProcessRequest(Purchase purchase);        /// <summary>        /// The set successor.        /// </summary>        /// <param name="successor">        /// The successor.        /// </param>        public void SetSuccessor(Approver successor)        {            this.Successor = successor;        }        #endregion    }    /// <summary>    /// The 'ConcreteHandler' class    /// </summary>    internal class Director : Approver    {        #region Public Methods and Operators        /// <summary>        /// The process request.        /// </summary>        /// <param name="purchase">        /// The purchase.        /// </param>        public override void ProcessRequest(Purchase purchase)        {            if (purchase.Amount < 10000.0)            {                Console.WriteLine("{0} approved request# {1}", this.GetType().Name, purchase.Number);            }            else if (this.Successor != null)            {                this.Successor.ProcessRequest(purchase);            }        }        #endregion    }    /// <summary>    /// The 'ConcreteHandler' class    /// </summary>    internal class VicePresident : Approver    {        #region Public Methods and Operators        /// <summary>        /// The process request.        /// </summary>        /// <param name="purchase">        /// The purchase.        /// </param>        public override void ProcessRequest(Purchase purchase)        {            if (purchase.Amount < 25000.0)            {                Console.WriteLine("{0} approved request# {1}", this.GetType().Name, purchase.Number);            }            else if (this.Successor != null)            {                this.Successor.ProcessRequest(purchase);            }        }        #endregion    }    /// <summary>    /// The 'ConcreteHandler' class    /// </summary>    internal class President : Approver    {        #region Public Methods and Operators        /// <summary>        /// The process request.        /// </summary>        /// <param name="purchase">        /// The purchase.        /// </param>        public override void ProcessRequest(Purchase purchase)        {            if (purchase.Amount < 100000.0)            {                Console.WriteLine("{0} approved request# {1}", this.GetType().Name, purchase.Number);            }            else            {                Console.WriteLine("Request# {0} requires an executive meeting!", purchase.Number);            }        }        #endregion    }    /// <summary>    /// Class holding request details    /// </summary>    internal class Purchase    {        // Constructor        #region Constructors and Destructors        /// <summary>        /// Initializes a new instance of the <see cref="Purchase"/> class.        /// </summary>        /// <param name="number">        /// The number.        /// </param>        /// <param name="amount">        /// The amount.        /// </param>        /// <param name="purpose">        /// The purpose.        /// </param>        public Purchase(int number, double amount, string purpose)        {            this.Number = number;            this.Amount = amount;            this.Purpose = purpose;        }        #endregion        // Gets or sets purchase amount        #region Public Properties        /// <summary>        /// Gets or sets the amount.        /// </summary>        public double Amount { get; set; }        /// <summary>        /// Gets or sets the number.        /// </summary>        public int Number { get; set; }        // Gets or sets purchase purpose        /// <summary>        /// Gets or sets the purpose.        /// </summary>        public string Purpose { get; set; }        #endregion    }}// Output:/*Director Larry approved request# 2034President Tammy approved request# 2035Request# 2036 requires an executive meeting!*/