Tuesday, January 29, 2008

Chain of Responsibility

This pattern is part of a group of patterns that deals with communication between two or more different objects. This pattern allows us to provide loose coupling between objects and also encourages testable code. In Chain of Responsibility we will have a chain of command objects that are passed requests. As we go down the chain....those objects that can handle the request do so....those that can't pass the request down the chain.

Our command objects will adhere to the ICommand interface. Any of the command objects that are part of the chain will have the 'Run' and 'Successor' methods defined in the interface.I can use the Successor method to allow us to setup the chain or we can use the constructor that is defined in each one of the following classes. I have chosen to simply utilize the constructor for simplicity.




public interface ICommand
{
ICommand Successor { get; set;}
void Run(int request);
}


I am going to define three different classes that will implement the ICommand interface.




public class EmailLogger: ICommand
{
private ICommand successor;


public EmailLogger()
{
}

public EmailLogger(ICommand successor)
{
this.successor = successor;
}

public ICommand Successor
{
get { return successor; }
set { successor = value; }
}

public void Run(int request)
{

if (request==1)
Console.WriteLine("I am the Email Logger. I can handle one.");
else if (successor != null)
successor.Run(request);
}


}


public class StdErrLogger: ICommand
{
private ICommand successor;


public StdErrLogger()
{
}

public StdErrLogger(ICommand successor)
{
this.successor = successor;
}

public ICommand Successor
{
get { return successor; }
set { successor = value; }
}

public void Run(int request)
{

if (request==2)
Console.WriteLine("I am the STD Error Logger. I can handle two.");
else if (successor != null)
successor.Run(request);
}
}

public class StdOutLogger : ICommand
{
private ICommand successor;


public StdOutLogger()
{
}

public StdOutLogger(ICommand successor)
{
this.successor = successor;
}

public ICommand Successor
{
get { return successor; }
set { successor = value; }
}

public void Run(int request)
{
if (request==3)
Console.WriteLine("I am the STD Out Logger. I can handle three.");
else if (successor!=null)
successor.Run(request);
}
}


You will notice that the meat of the object for the chain to work according to the pattern is each of the Run methods. It is here we will check the original request. If our current object in the chain can handle the request...it will...otherwise we will pass on the request to the rest of the chain.

I am going to define a place where I can kick off the chain creation. This chain could also be created separately as part of some factory class.



public class ChainOfResponsibility
{
private ICommand stdOutLogger;

public void Initialize(int request)
{

stdOutLogger = new StdOutLogger(new EmailLogger(new StdErrLogger()));
stdOutLogger.Run(request);
}

}


The 'StdOutLogger' is the outmost part of the chain and will start everything off. Calling Run here...we will check the request. Let's say that the request is '3' coming from the Initialize method. StdOutLogger can't really handle this value...so it passes the request off to EmailLogger. EmailLogger's Run method can't handle this value either. The request is finally passed on to StdErrLogger which can handle three.

** Note that based on our code...once a request is dealt with no other command objects are called.**

0 Comments:

Post a Comment

<< Home