Reader Level:
ARTICLE

Chain of Responsibility Pattern

Posted by Jean Paul Articles | Design & Architecture November 28, 2011
Chain of Responsibility is one among the 23 Design Patterns by Gang of Four. It is an interesting pattern and similar to the Observer pattern. In this article we are exploring the Chain of Responsibility pattern.
  • 0
  • 0
  • 11547
Download Files:
 

Chain of Responsibility is one among the 23 Design Patterns by Gang of Four. It is an interesting pattern and similar to the Observer pattern. In this article we are exploring the Chain of Responsibility pattern.

I am using the same Challenge and Solution style for explaining this pattern.

Challenge

You are working on an application in which the Logic class generates various messages. The messages are of two types.

  • Normal Priority
  • High Priority

The Normal Priority messages are to be processed by Logger class and High Priority messages by Emailer class.

You have to make the design in such a way that the Logic class need not think about right handler of the message. It will just send the message.

How the design will proceed?

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

Control Flow

RsnPtt1.gif

Implementation

Following is the definition for the Logic class:

public class Logic
{
    public IReceiver Receiver;

    public void CreateMessage(Message message)
    {
        if (Receiver != null)
            Receiver.HandleMessage(message);
    }
}


We can see from the above code that the Logic class has a property of type IReceiver. On the CreateMessage method this Receiver is used to handle the message. So only one receiver is registered by the Logic class instance.

Following are the definition of Message class and MessagePriority enumeration:

public class Message
{
    public string Text;
    public MessagePriority Priority;
}

public enum MessagePriority
{
    Normal,
    High
}

Following are the Receiver Interface and Implementation classes:

public interface IReceiver
{
    bool HandleMessage(Message message);
}

public class Logger : IReceiver
{
    private IReceiver _nextReceiver;

    public Logger(IReceiver nextReceiver)
    {
        _nextReceiver = nextReceiver;
    }

    public bool HandleMessage(Message message)
    {
        if (message.Priority == MessagePriority.Normal)
        {
            Trace.WriteLine(message.Text + " : Logger processed it!");
            return true;
        }
        else
        {
            if (_nextReceiver != null)
                _nextReceiver.HandleMessage(message);
        }

        return false;
    }
}

public class Emailer : IReceiver
{
    private IReceiver _nextReceiver;

    public Emailer(IReceiver nextReceiver)
    {
        _nextReceiver = nextReceiver;
    }

    public bool HandleMessage(Message message)
    {
        if (message.Priority == MessagePriority.High)
        {
            Trace.WriteLine(message.Text + " : Emailer processed it!");
            return true;
        }
        else
        {
            if (_nextReceiver != null)
                _nextReceiver.HandleMessage(message);
        }

        return false;
    }
}


From the above code we can see that each receiver class checks the message priority and processes it. If the priority is not matching it is send to the next receiver in the chain.

Here each receiver takes care of passing the unprocessed message. The next receiver is stored through the constructor of each receiver.

The chain will be executed until:

  • Message is processed

  • Receiver chain exhausted

Code Execution

The windows forms application attached can be used to test the control flow.

RsnPtt2.gif

Here the chain is built as following:

  • Logic class holds first receiver which is Logger

  • Logger class holds the next receiver which is Emailer

  • Emailer class have null receiver denoting end of chain

The following code depicts the above chain creation:

Logic logic = new Logic();
logic.Receiver = new Logger(new Emailer(null));



Note: Please note that the advantage of this pattern is decoupling of sender and receiver. The sender does not think about the right receiver. Instead it will pass the request and the appropriate receiver should process it. The above example can be written using a list of receivers in the Logic class with a Boolean property mentioning whether the message is processed or not.

Comparing Observer and Chain of Responsibility

In the case of Observer pattern all the registered receivers will get the request. Each of the receivers is interested in processing it. But in chain of responsibility the request is passed until it is not processed.

RsnPtt3.gif

Summary

In this article we have explored Chain of Responsibility pattern with a C# example. The associated source code contains the example we discussed.
 

COMMENT USING

Trending up