Friday, August 28, 2009

Chain of responsibility pattern in c# .Net

Intent
The Chain of Responsibility pattern avoids coupling the sender of a request to the receiver.

Non-Software Example
A mechanical sorting used by banks is an example for chain of responsibility pattern. In a sorting machine there is single slot for all the coins. As each coin is dropped a chain of responsibility it determines which tube to accommodate each coin. If a tube cannot accommodate the coin, it is passed to next one until a tube can accept the coin. Here the coin corresponds to the requestor. Each tube corresponds to the chain of concrete handlers.




Benefits
Here if you observe the coupling between the coin slot and coin tube is reduced. Although there are four slots only one slot is used. The are no explicit receivers for the coin. It might happen that the coin is not accommodated in any of the tubes and the coin comes out. With chain of responsibility receipt is not guaranteed always.
As we discussed chain of responsibility promotes loose coupling by allowing a series of handlers to be created in a linked chain. The request is passed to the first handler in the chain, which will either process it or pass it on to its successor. This continues until the request is processed or the end of the chain is reached. The handler responsible for the final processing of the request and

UML

Let us look into the classes
Client: The client class is the one who generates the request. If you consider our previous example the coin is the client.

HandlerBase: the Handler base is an abstract base class for the concrete handler classes. It contains a member that that holds the next concrete handler (in the UML it is ConcreteHandlerA or ConcreteHandlerB) in the chain and an associated method to set its successor. It includes a abstract which has to implemented by the concrteHandler classes. The implementation of this method would be either handle the request or pass it to the next object in the chain.

ConcreteHandler Class: There can be many concrete handler classes that inherit from handle base class. This Handle request method in this class will handle request and if not will pass it to the next successor.

Software Example & Explanation of Code

Let us consider a most frequently used code where we can see the chain of responsibility pattern. Let us say you have a try… catch block in “MethodA”. Let us say your code looks like this

MethodA
{
Try
{
MethodB();
//Some other Code
}
catch(exception ex)
{

}

Here is MethodB code

MethodB
{
Try
{
MethodB();
//Some other Code
}
catch(exception ex)
{

}


Now let us say you have an error in MethodB. So here there is a chain of try..Catch block. So when an error in MethodB occurs it goes to exception of B and since the call was generated it goes to the successor i.e. MethodA catch block.

Let us consider another example. Let us say you are building an application for an organization. The key players in the organization are HR Managers who can add an employee, HR Director who can modify the employee details and HR Vice president who can delete an employee entry from the system. Definitely this can be achieved with an if ..else condition, but as the code grows this becomes unmanageable. Let us create the classes one by one. All the classes and methods are self explanatory so we will get into explanation of code. First the operation types.

public enum RequestType
{
ADD=1,
MODIFY=2,
DELETE=3
}

Next is the abstract class. This is the “HandlerBase” class of the above UML

Approver.cs
public abstract class Approver
{
string _Name;
Approver _NextApprover;

public string Name
{
get { return _Name; }
set { _Name = value; }
}


public Approver(string appName)
{
_Name = appName;
}

public Approver NextApprover
{
get { return _NextApprover;}
}
public void SetNextApprover(Approver nextApprover)
{
_NextApprover = nextApprover;
}

public abstract void Approve(ref EmployeeChangeRequest changeReq);

}

Next are the classes implementing the abstract class, the Manager, Director and VicePresident class.

Manager.cs
public class Manager:Approver
{
public Manager(string name)
: base(name)
{ }

public override void Approve(ref EmployeeChangeRequest changeReq)
{
if (changeReq.RequestType.Equals(RequestType.ADD))
{
changeReq.IsApproved = true;
}
else
{
if (NextApprover != null)
NextApprover.Approve(ref changeReq);
}
}
}

Director.cs
public class Director:Approver
{
public Director(string name)
: base(name)
{ }

public override void Approve(ref EmployeeChangeRequest changeReq)
{
if (changeReq.RequestType.Equals(RequestType.ADD) changeReq.RequestType.Equals(RequestType.MODIFY))
{
changeReq.IsApproved = true;
}
else
{
if (NextApprover != null)
{
NextApprover.Approve(ref changeReq);
}
}
}
}


VicePresident.cs
public class VicePresident:Approver
{
public VicePresident(string name)
: base(name)
{ }

public override void Approve(ref EmployeeChangeRequest changeReq)
{
if (changeReq.RequestType.Equals(RequestType.ADD) changeReq.RequestType.Equals(RequestType.MODIFY) changeReq.RequestType.Equals(RequestType.DELETE))
{
changeReq.IsApproved = true;
}
}
}


Now the employee class to which we want a change
public class EmployeeChangeRequest
{
int _requestID;
RequestType _requestType;
string _strRequestMessage;
bool _isApproved;

public EmployeeChangeRequest(int requestId, RequestType requestType, string RequestMessage)
{
_requestID = requestId;
_requestType = requestType;
_strRequestMessage = RequestMessage;
}

public int RequestID
{
get { return _requestID; }
set { _requestID = value; }
}

public RequestType RequestType
{
get { return _requestType; }
set { _requestType = value; }
}

public string StrRequestMessage
{
get { return _strRequestMessage; }
set { _strRequestMessage = value; }
}

public bool IsApproved
{
get { return _isApproved; }
set { _isApproved = value; }
}

}


Okay now we are all set to see the chain. Let us create a client for this set the values as shown. Please note the values are being passed as reference type in the abstract class

Manager objManager = new Manager("Manager1");
Director objDirector = new Director("Director1");
VicePresident objVp = new VicePresident("VP1");

objManager.SetNextApprover(objDirector);
objDirector.SetNextApprover(objVp);

//We are setting the delete type and calling the Manager class to approve
EmployeeChangeRequest objEmp = new EmployeeChangeRequest(123, RequestType.DELETE, "Employee with ID 123 is quiting, Please delete the data");

objManager.Approve(ref objEmp);


Now here in the client we are making a delete operation which only the Vice President has access to. But we are calling the approve method of manager class. So up on the call of approve method it will pass it to Approve method of director class and since director is also not authorized to delete it goes next to the Vice president class where it gets executed.

The entire source code is available @

http://www.csharppatterns.com/

Happy Coding.



No comments: