Friday 17 December 2010

Chain of Responsibility Pattern

"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."


The client doesn't care which handler handles the request because the handler communicates with an abstraction.  This decoupling allows new handlers to be inserted into the chain of potential handlers, old ones to be deleted, or the ordering to be changed.
In the example below Dog is the Handler class and the ConcreteHandlers are Runt, and AlphaDog. The AlphaDog "Jess" gets first chance to HandleRequest (FetchBall). If Jess can't be bothered then second in command is allowed to fetch the ball ("Dot" the English Pointer). Finally, "Royston" the poor old Labrador gets to fetch the ball.  He has no choice as there is no dog he can delegate the ball-fetching to.

using System;
 
namespace ChainOfResponsibility
{
    class Program
    {
        static void Main(string[] args)
        {
            Dog labrador = new Runt("Royston");
            Dog englishPointer = new AlphaDog(labrador, "Dot");
            Dog borderCollie = new AlphaDog(englishPointer, "Jess");
 
            for (int i = 0; i < 20; i++)
            {
                borderCollie.FetchBall();               
            }
 
            Console.ReadLine();
        }
    }
 
    public abstract class Dog
    {
        static Random randomSeed = new Random();
 
        protected Dog _secondInCommand;
        protected string _name;
 
        public Dog(string name, Dog secondInCommand)
        {
            _secondInCommand = secondInCommand;
            _name = name;
        }
 
        public abstract void FetchBall();
 
        protected bool CanBeBothered()
        {
            return Dog.randomSeed.NextDouble() > 0.5;
        }      
    }
 
    public class AlphaDog : Dog
    {
        public AlphaDog(Dog secondInCommand, string name) : 
        base(name, secondInCommand) { }
 
        public override void FetchBall()
        {         
            if (! CanBeBothered())
            {
                _secondInCommand.FetchBall();
            }
            else
            {
                Console.WriteLine("{0} fetched it.", _name);
            }
        }
    }  
 
    public class Runt : Dog
    {
        public Runt(string name) : base(name, null) { }
 
        public override void FetchBall()
        {
            Console.WriteLine("{0} fetched it.", _name);
        }
    }   
}

Outputs:

Royston fetched it.
Royston fetched it.
Dot fetched it.
Royston fetched it.
Jess fetched it.
Dot fetched it.
Royston fetched it.
Jess fetched it.
Jess fetched it.
Jess fetched it.
Dot fetched it.
Jess fetched it.
Jess fetched it.
Royston fetched it.
Jess fetched it.
Royston fetched it.
Jess fetched it.
Jess fetched it.
Jess fetched it.
Dot fetched it.

 

No comments:

Post a Comment