BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

Design Patterns
.NET 1.1+

Chain of Responsibility Design Pattern

The chain of responsibility pattern is a design pattern that defines a linked list of handlers, each of which is able to process requests. When a request is submitted to the chain, it is passed to the first handler in the list that is able to process it.

Example Chain of Responsibility

In this section we will create an example of the chain of responsibility design pattern using C#. This example will implement the coin handling system described earlier in the article. The request will be a Coin object with a weight in grammes and diameter in millimetres. We can create the coin class using the code below. This uses C# 3.0's automatically implemented property syntax for brevity. If you are using .NET 2.0 or earlier you should expand these into fully defined properties.

public class Coin
{
    public float Weight { get; set; }
    public float Diameter { get; set; }
}

We can now create the base class for the handlers. This is similar to the previous HandlerBase class described above. The key difference is that the request is a Coin object rather than an integer.

public abstract class CoinHandlerBase
{
    protected CoinHandlerBase _successor;

    public abstract void HandleCoin(Coin coin);

    public void SetSuccessor(CoinHandlerBase successor)
    {
        _successor = successor;
    }
}

Finally we can add the individual handlers for the coins. To prevent the sample from becoming too large, we will handle the UK 5p, 10p, 20p, 50p and one pound coins. Other coins will be rejected. Each handler will use the weight and diameter of the coin with some allowance for the coin being slightly too large, small, light or heavy. When a handler recognises a coin it will write a message to the console describing the action that would be taken in the real system.

public class FivePenceHandler : CoinHandlerBase
{
    public override void HandleCoin(Coin coin)
    {
        if (Math.Abs(coin.Weight - 3.25) < 0.02 && Math.Abs(coin.Diameter - 18) < 0.1)
            Console.WriteLine("Captured 5p");
        else if (_successor != null)
            _successor.HandleCoin(coin);
    }
}


public class TenPenceHandler : CoinHandlerBase
{
    public override void HandleCoin(Coin coin)
    {
        if (Math.Abs(coin.Weight - 6.5) < 0.03 && Math.Abs(coin.Diameter - 24.5) < 0.15)
            Console.WriteLine("Captured 10p");
        else if (_successor != null)
            _successor.HandleCoin(coin);
    }
}


public class TwentyPenceHandler : CoinHandlerBase
{
    public override void HandleCoin(Coin coin)
    {
        if (Math.Abs(coin.Weight - 5) < 0.01 && Math.Abs(coin.Diameter - 21.4) < 0.1)
            Console.WriteLine("Captured 20p");
        else if (_successor != null)
            _successor.HandleCoin(coin);
    }
}


public class FiftyPenceHandler : CoinHandlerBase
{
    public override void HandleCoin(Coin coin)
    {
        if (Math.Abs(coin.Weight - 8) < 0.02 && Math.Abs(coin.Diameter - 27.3) < 0.15)
            Console.WriteLine("Captured 50p");
        else if (_successor != null)
            _successor.HandleCoin(coin);
    }
}


public class OnePoundHandler : CoinHandlerBase
{
    public override void HandleCoin(Coin coin)
    {
        if (Math.Abs(coin.Weight - 9.5) < 0.02 && Math.Abs(coin.Diameter - 22.5) < 0.13)
            Console.WriteLine("Captured £1");
        else if (_successor != null)
            _successor.HandleCoin(coin);
    }
}

Testing the Chain of Responsibility

To test the chain of responsibility we can use a console application as the client and execute code from the Main method. Try running the following code to see the chain's reaction to various coin sizes. Note that any unrecognised coins are simply ignored. In the real-world system this would cause the return of the coin.

CoinHandlerBase h5 = new FivePenceHandler();
CoinHandlerBase h10 = new TenPenceHandler();
CoinHandlerBase h20 = new TwentyPenceHandler();
CoinHandlerBase h50 = new FiftyPenceHandler();
CoinHandlerBase h100 = new OnePoundHandler();
h5.SetSuccessor(h10);
h10.SetSuccessor(h20);
h20.SetSuccessor(h50);
h50.SetSuccessor(h100);

Coin tenPence = new Coin { Diameter = 24.49F, Weight = 6.5F };
Coin fiftyPence = new Coin { Diameter = 27.31F, Weight = 8.01F };
Coin counterfeitPound = new Coin { Diameter = 22.5F, Weight = 9F };

h5.HandleCoin(tenPence);
h5.HandleCoin(fiftyPence);
h5.HandleCoin(counterfeitPound);

/* OUTPUT

Captured 10p
Captured 50p

*/
16 July 2009