The chain of responsibility pattern

The chain of responsibility pattern promotes loose coupling by separating the request senders from the request receivers and processors. It works like how a sender sends a request to be fulfilled to one of the receiver objects, and this object either fulfills the request and returns, or it partially fulfills the request, does not process the request, and sends the request to the next request receiver/processor object until it has been handled. In this way, all the request receivers, processors, or handlers are chained to each other.

A more common example of this pattern is this: say, we have a request to purchase an item and it requires an approval; it depends on the value of an item whether it can be approved by a manager, SVP, or CEO. So in this scenario, we send the request for approval to a manager first; if he can fulfill the request, it is satisfied there. Otherwise, the manager sends the request to its successor, SVP, and so on to all the connected request receiver objects automatically, while the request sender does not know where it should be actually handled and all the receivers chained together work smoothly until it has been completely handled.

Let's take a look at the UML class diagram for the chain of responsibility pattern:

The class diagram is simple; the client who is the request sender basically has the instance of one request and sends the command to it; one request handler keeps the instance of another request handler, and so on. Note that in this way, request handlers are chained together and, therefore, processing can take place only sequentially and only in one direction.

As mentioned earlier, in a chain of responsibility, either the request handler can skip and pass the request to its successor, or it can process it or partially process and pass it forward to the next one in the chain.

We will now take a fairly practical example for the chain of responsibility pattern. Let's say we have some kind of an app that needs to display the weather information containing various attributes such as the map, temperature, and so on. In our example, we will fill the request command object partially by each request handler, and when it reaches the last one, the request is fulfilled.

This is what our example request command object looks like:

    public class WeatherStructure 
{
public WeatherStructure()
{
Temperature = new Temperature();
Map = new Map();
WeatherThumbnail = new WeatherThumbnail();
WeatherDescription = new WeatherDescription();
}

public Temperature Temperature;
public Map Map;
public WeatherThumbnail WeatherThumbnail;
public WeatherDescription WeatherDescription;
}

We will fill each of the four attributes one by one by four request handlers chained together. The interface for the request handler for our example is as follows:

    public abstract class IWeatherInfoBuilder 
{
protected IWeatherInfoBuilder _successor;

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

public abstract void BuildWeatherObject(WeatherStructure ws);
}

One of the request handlers looks like this, while all other request handlers look and work the same way:

    public class WeatherMapBuilder : IWeatherInfoBuilder 
{
public override void BuildWeatherObject(WeatherStructure ws)
{
BuildMap(weatherStructure.Map);

if (_successor != null)
_successor.BuildWeatherObject(weatherStructure);
}

private void BuildMap(Map map)
{
//construct Map appropriately
map.MapURL = "https://maps.google.com/";
}
}

Note how the request handlers are chained together: first, the successive request handler is taken and saved in SetSuccessor() and used for chained processing; when the request is being handled in BuildWeatherObject() after the handling is done, the successor is invoked because, in this example, we are processing the request command partially by each of the request handlers.

Let's take a look at what the client code looks like and who acts as a request command object sender:

    public void Test_ChainOfResponsibility_Pattern() 
{
IWeatherInfoBuilder wInfoBuilder1 = new
WeatherDescriptionBuilder();
IWeatherInfoBuilder wInfoBuilder2 = new
WeatherMapBuilder();
IWeatherInfoBuilder wInfoBuilder3 = new
WeatherTemperatureBuilder();
IWeatherInfoBuilder wInfoBuilder4 = new
WeatherThumbnailBuilder();

wInfoBuilder1.SetSuccessor(wInfoBuilder2);
wInfoBuilder2.SetSuccessor(wInfoBuilder3);
wInfoBuilder3.SetSuccessor(wInfoBuilder4);

WeatherStructure weather = new WeatherStructure();
wInfoBuilder1.BuildWeatherObject(weather);
}

The client code is simple and all the chained request processing is achieved by a single line--wInfoBuilder1.BuildWeatherObject(weather);

Chained request handlers fill each attribute of WeatherStructure one by one.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.22.145