Design patterns: Chain of responsibility

Today will be the theme, as I promised in the previous article, about the design pattern called a chain of obligations, also known as the chain of responsibility, it is perfect for assigning responsibilities to every employee in the company, well …we’re going with the topic

Admission

At the beginning of the introduction, some people accused me of having some too complicated terminology in my entries and wouldn’t recommend it to beginners, or more precisely to those who are just learning to program. Of course, the design patterns are not for beginners in programming, mainly because the beginners usually do everything in a way, “as only as it works”, design patterns are for people who have happen to write some dirty code and such people will already know, that doing everything in a way “as only as it works” has very short legs.

And, if someone does not know what an abstract class or interface is, let’s not take for design patterns too because these concepts are used in most of the patterns. I try to write in a simple language, but in programming and especially in design patterns, it is very difficult and to understand a given pattern sometimes you need to use this complicated terminology a little, but if I do something what somehow will be something incomprehensible even for people who already sit a little subject, of course I am open to any comments, you can contact me on the Contact page or simply write in the comments. And that would be all in the introduction. Let’s go to the pattern overview.

Discussion

The chain of responsibility is used to transfer tasks in the objects chain(hence the name of the pattern) and depending on the task received, the object that received the task checks whether it fulfills the condition for completing the task, if not, forward the request to subsequent objects. The picture below illustrates it well.

The client sends request and all objects in turn check whether they are authorized to perform this request and the main part of the pattern implementation consists of a linked list and an abstract class that can be said to be a template for this list.

And just to understand this pattern you need to know what a linked list is.

Linked list

A linked list is a structure in which each element knows the address of the next element.

The .NET platform is ready, implemented a one-way list, for those who write in C++, here is an example of a linked list, also in other languages the implementation may look different, well, everyone must to match the implementation of a linked list to own language. But generally a description of all examples of design patterns can be easily transferred from C# to Python, C++, Java, etc.

Design patterns and practice of writing clean code will be useful to everyone regardless of language.

The example below:

namespace LinkedList
{
class Program
{
static void Main(string[] args)
{
var tune = new LinkedList<string>();
            tune.AddFirst("do"); // do
tune.AddLast("so"); // do - so
tune.AddAfter(tune.First, "re"); // do - re- so
tune.AddAfter(tune.First.Next, "mi"); // do - re - mi- so
tune.AddBefore(tune.Last, "fa"); // do - re - mi - fa- so
tune.RemoveFirst(); // re - mi - fa - so
tune.RemoveLast(); // re - mi - fa
            LinkedListNode<string> miNode = tune.Find("mi");
            tune.Remove(miNode); // re - fa
tune.AddFirst(miNode); // mi- re - fa
            foreach (string s in tune)
Console.WriteLine(s);
            Console.ReadKey();
}
}
}

This is an example of a linked list, each element of the list knows the address of the next element, in the above example first we adding elements to the list at the beginning, then add the next element to the first element of the list and add another element to the previously added element, notice what happens happens, every element of the list knows what its next element is.

Result:

Similarly, the pattern chain of responsibility works in this way, it is known where to forward client requests, in this case to the next object in the structure.

I think I know how often you feel when you learn design patterns, probably like this sir below

Relax, it’s not so terrible despite appearances, let’s move on

Intent

  • Support sent request by the objects chain that provides the request support or forwards it.
  • Sending a request to a chain that contains many handlers (objects that can handle the request)

Problem

You can use the object chain pattern as it was in the introduction to manage tasks, or there where are wherever there are mechanisms with similar requests, imagine a situation where we must effectively handle a largenumber of requests without having to write classes with dependencies.

Use when:

  • You want to assign tasks to different objects quickly and easy.
  • For example, you want to implement a request processing engine in which it will be easy to add support new types, or if necessary, remove them.

Structure

The pattern diagram of the chain of responsibility consists of:

  • An abstract class of Handler in which the handle() method is defined, which send requests further if the request does not match a given object and a linked list whose elements are objects in the chain, each object knows what is the next object in the list.
  • Classes that inherit from the Handler class and which process requests, if the request matches, they process it if they do not forward to the next object in the queue.

Below, an example of a chain pattern. It is simple example so that you can easily understand it.

The equivalent of the Handler class from the UML diagram is the Number class. It stores the object from the chain and defines the method forwarding the request.

namespace ChainOfResponsibilitySchema
{
abstract class Number
{
protected Number number;
        public void setNumber(Number number)
{
this.number = number;
}
        public abstract void ForwardRequest(TypeNumber typenumber);
}
}

The classes of the chain are classes One, Two, Three.

namespace ChainOfResponsibilitySchema
{
class One : Number
{
public override void ForwardRequest(TypeNumber typenumber)
{
if (typenumber == TypeNumber.One)
{
Console.WriteLine("The first request is supported");
}
else if (number != null)
{
number.ForwardRequest(typenumber);
}
}
}
    class Two : Number
{
public override void ForwardRequest(TypeNumber typenumber)
{
if (typenumber == TypeNumber.Two)
{
Console.WriteLine("The second request is supported");
}
else if (number != null)
{
number.ForwardRequest(typenumber);
}
}
}
    class Three : Number
{
public override void ForwardRequest(TypeNumber typenumber)
{
if (typenumber == TypeNumber.Three)
{
Console.WriteLine("The third request is supported");
}
else if (number != null)
{
number.ForwardRequest(typenumber);
}
}
}
}

All of these classes inherit from the Number class, thanks to which they can pass on requests further.

And launching that in the client.

namespace ChainOfResponsibilitySchema
{
public enum TypeNumber
{
One,
Two,
Three
}
    class Program
{
static void Main(string[] args)
{
//Initializing objects
Number one = new One();
Number two = new Two();
Number three = new Three();
            //Setting elements of a one-way list
one.setNumber(two);
two.setNumber(three);
            //An example of a set of numbers
List<TypeNumber> QuestsOnToday = new List<TypeNumber> {
TypeNumber.One,
TypeNumber.Two,
TypeNumber.Three
};
            //Seek the right number
foreach (var quest in QuestsOnToday)
{
one.ForwardRequest(quest);
}
            Console.ReadKey();
}
}
}

In the client, we first create instances of classes belonging to the chain, and save these objects in a linked list, so that the next object to which we forward the request knows what is next, just to know to which object to forward the request. We have saved the types of requests in the enum enumeration type in the QuestsOnToday list.

Finally, we pass the requests in the foreach loop one by one.

Result:

Advantages

  • When a client sends a request, the client doesn’t know which of the objects will handle it.
  • The possibility of an easy and flexible allocation of responsibilities to Handle objects (that is, objects that support customer requests).

Disadvantages

  • The lack of a guarantee of request handle, thus also the operation of the chain is more difficult to debug.

Example

Payments for employees

In this example, we will be checking, what payment on which position who should get, that is, if we enter in the console 4000, we check that the payout is 4000, for example for a director.

The equivalent of the Handler class from the UML diagram looks like this.

namespace Purchase
{
abstract class PurchasePower
{
protected static double BASE = 500;
protected PurchasePower successor;
        abstract protected double getAllowable();
abstract protected string getRole();
        public void setSuccessor(PurchasePower successor)
{
this.successor = successor;
}
        public void processRequest(PurchaseRequest request)
{
if (request.getAmount() < getAllowable())
{
Console.WriteLine(getRole() + " will approve $" + request.getAmount());
}
else if (successor != null)
{
successor.processRequest(request);
}
}
}
}

The object chain looks like this.

namespace Purchase
{
class DirectorPPower : PurchasePower
{
protected override double getAllowable()
{
return BASE * 20;
}
        protected override string getRole()
{
return "Director";
}
}
    class ManagerPPower : PurchasePower
{
protected override double getAllowable()
{
return BASE * 10;
}
        protected override string getRole()
{
return "Manager";
}
}
    class PresidentPPower : PurchasePower
{
protected override double getAllowable()
{
return BASE * 60;
}
        protected override string getRole()
{
return "President";
}
}
    class VicePresidentPPower : PurchasePower
{
protected override double getAllowable()
{
return BASE * 40;
}
        protected override string getRole()
{
return "Vice President";
}
}
}

We see that it looks similar to the previous example with the diagram, but it differs a bit, mainly the redirecting method already has a body in the abstract class PurchasePower and is not extended by each object in the chain.

Let’s look at how it looks in the client.

namespace Purchase
{
class Program
{
static void Main(string[] args)
{
ManagerPPower manager = new ManagerPPower();
DirectorPPower director = new DirectorPPower();
VicePresidentPPower vp = new VicePresidentPPower();
PresidentPPower president = new PresidentPPower();
manager.setSuccessor(director);
director.setSuccessor(vp);
vp.setSuccessor(president);
            try
{
while (true)
{
Console.WriteLine("Enter the amount to check who should approve your expenditure.");
Console.Write(">");
double d = double.Parse(Console.ReadLine());
manager.processRequest(new PurchaseRequest(d));
}
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
            Console.ReadKey();
}
}
}

It also looks similar to the previous example, but differs in that while in a while loop we enter the value, it is saved in the PurchaseRequest class object and then it is sent to the PurchasePower class to the processRequest() method.

And let’s see what the PurchaseRequest class looks like.

namespace Purchase
{
class PurchaseRequest
{
        private double amount;
private string purpose;
        public PurchaseRequest(double amount)
{
this.amount = amount;
}
        public double getAmount()
{
return amount;
}
        public void setAmount(double amount)
{
this.amount = amount;
}
}
}

It can be seen that payment data is saved in this class, we can display or set it. Analyze this example exactly, always will be a link at the end of the lesson to github with all the examples.

Result:

Real-life example

Withdrawal from an ATM

We will make another example on the principle of withdrawing money from an ATM, we will be send requests that will be check what the user chose.

First, abstract class Pay, which is a linked list template, and defines a method that redirects requests to subsequent objects.

namespace PayMoney
{
abstract class Pay
{
protected Pay pay;
        public void setPayOut(Pay pay)
{
this.pay = pay;
}
        public abstract void ForwardRequest(QuantityPayingMoney  quantitypayingmoney);
}
}

And of course, a chain of objects that check sent requests.

namespace PayMoney
{
class PayFive : Pay
{
public override void ForwardRequest(QuantityPayingMoney quantitypayingmoney)
{
if (quantitypayingmoney == QuantityPayingMoney.PayFive)
{
Console.WriteLine("Pay out five dolars from cashpoint");
}
else if (pay != null)
{
pay.ForwardRequest(quantitypayingmoney);
}
}
}
    class PayTwenty : Pay
{
public override void ForwardRequest(QuantityPayingMoney quantitypayingmoney)
{
if (quantitypayingmoney == QuantityPayingMoney.PayTwenty)
{
Console.WriteLine("Pay out twenty dolars from cashpoint");
}
else if (pay != null)
{
pay.ForwardRequest(quantitypayingmoney);
}
}
}
    class PayFifty : Pay
{
public override void ForwardRequest(QuantityPayingMoney quantitypayingmoney)
{
if (quantitypayingmoney == QuantityPayingMoney.PayFifty)
{
Console.WriteLine("Pay out fifty dolars from cashpoint");
}
else if (pay != null)
{
pay.ForwardRequest(quantitypayingmoney);
}
}
}
    class PayHundred : Pay
{
public override void ForwardRequest(QuantityPayingMoney quantitypayingmoney)
{
if (quantitypayingmoney == QuantityPayingMoney.PayHundred)
{
Console.WriteLine("Pay out hundred dolars from cashpoint");
}
else if (pay != null)
{
pay.ForwardRequest(quantitypayingmoney);
}
}
}
}

And running everything in the client.

namespace PayMoney
{
enum QuantityPayingMoney
{
PayHundred,
PayFifty,
PayTwenty,
PayFive
}
class Program
{
static void Main(string[] args)
{
//Initializing objects
Pay payHundred = new PayHundred();
Pay payFifty = new PayFifty();
Pay payTwenty = new PayTwenty();
Pay payFive = new PayFive();
            //Setting elements of a one-way list
payHundred.setPayOut(payFifty);
payFifty.setPayOut(payTwenty);
payTwenty.setPayOut(payFive);
            string option = Console.ReadLine();
            if (option=="1")
{
payHundred.ForwardRequest(QuantityPayingMoney.PayHundred);
}
else if (option == "2")
{
payHundred.ForwardRequest(QuantityPayingMoney.PayFifty);
}
else if (option == "3")
{
payHundred.ForwardRequest(QuantityPayingMoney.PayTwenty);
}
else if (option == "4")
{ payHundred.ForwardRequest(QuantityPayingMoney.PayFive);
}
            Console.ReadKey();
}
}
}

So the procedure is similar to the one shown in the chain master scheme, we have an abstract Pay class, which is the equivalent of the Handle class from the UML diagram and we have a chain of classes that inherit from the Pay class. And we create class instances in the client and write them on the principle of a linked list, and the client chooses the option how much money he wants to pay out depending on what he chose we send the request, which each object in the chain checks in turn, starting from the PayHundred class because it is first in line.

Result

Summary

That’s all about on subject the Chain of responsibility pattern

Link to github with all examples: https://github.com/Slaw145/ChainOfResponsibilityTutorial

This content also you can find on my steemit blog https://steemit.com/design-patterns/@slawas/design-patterns-chain-of-responsibility

And on my blog devman: http://devman.pl/programtech/design-patterns-chain-responsibility/

If you have endured to the end, he congratulates you. If you have read about other design patterns on this blog and you’ve study them and you understand all of them, then you’re not a beginner programmer anymore, but you already have a certain skill.

In the next article, we will talk about the Mediator design pattern.

As a standard, I remind you about the newsletter, which I send notifications about new entries and additional information about the IT world in general.

And NECESSERILY join the DevmanCommunity community on fb, part of the community is in one place

– site on fb: Devman.pl-Sławomir Kowalski

– group on fb: DevmanCommunity

Ask, comment underneath at the end of the post, share it, rate it, whatever you want.