Java design pattern: Chain of responsibility

Today we will look at the first Java design pattern from the category of behavioral patterns – Chain of Responsibility. Design patterns in this category deal with the communication (interaction) between objects and their responsibility.

What is the Chain of Responsibility design pattern?

The Chain of Responsibility design pattern is a pattern that allows multiple objects to process requests without the need for the object to know who its follower in the chain is. Each object in the chain has the ability to process the request, but if it doesn’t know how to process it, it passes it on to the next object in the chain.

What problem does the Chain of Responsibility design pattern solve?

It solves the problem of processing requests in a chain, so that instead of the request being sent to a specific object, the request travels through a chain of objects, where each object in the chain can be responsible for processing the request, but if it doesn’t process it, it will pass it on to the next object in the chain. The goal is to allow multiple objects to process a request without having to specify exactly which object will process it, thus reducing the interdependency between the sender and receiver of the request.

Example of Chain of Responsibility implementation in Java

Now we will write a program that will simulate the approval of employee requests in a company using the Chain of Responsibility design pattern. The goal of this pattern is to allow multiple objects to process a request without knowing exactly which object will process it. The objects are chained together, and each object in the chain decides whether it can handle the request or pass it on to the next object in the chain.

There are three types of employees in this program – Employee, Supervisor and Director, each of which implements an abstract class, ApproverRequirements, which contains common functionality for all employees.

SchvalovatelPoziadavky.java

package designpatterns;

public abstract class SchvalovatelPoziadavky {
    String meno;
    SchvalovatelPoziadavky dalsiSchvalovatel;
    private SchvalovatelPoziadavky(){

    }
    public SchvalovatelPoziadavky(String meno){
        this.meno = meno;
    }
    public abstract void nastavitDalsiehoSchvalovatela(SchvalovatelPoziadavky dalsiSchvalovatel);

    public void posuditPoziadavku(String poziadavka)
    {
        if(this.dalsiSchvalovatel != null)
            this.dalsiSchvalovatel.posuditPoziadavku(poziadavka);
        else
            System.out.println(poziadavka + " - poziadavka bola zamietnuta!");
    }
}

The ApproverRequirements abstract class defines common methods and contains a reference to the next approver in the chain.

Zamestnanec.java

package designpatterns;

public class Zamestnanec extends SchvalovatelPoziadavky {
    public Zamestnanec() {
        super("zamestnanec");
    }
    @Override
    public void nastavitDalsiehoSchvalovatela(SchvalovatelPoziadavky dalsiSchvalovatel) {
        this.dalsiSchvalovatel = dalsiSchvalovatel;
    }
    @Override
    public void posuditPoziadavku(String poziadavka) {
        if(poziadavka == "NAVSTEVA_LEKARA") {
            System.out.println(poziadavka + " - " + meno + " schvalil poziadavku");
        }
        else {
            super.posuditPoziadavku(poziadavka);
        }
    }
}

Veduci.java

package designpatterns;

public class Veduci extends SchvalovatelPoziadavky {
    public Veduci() {
        super("veduci");
    }
    @Override
    public void nastavitDalsiehoSchvalovatela(SchvalovatelPoziadavky dalsiSchvalovatel) {
        this.dalsiSchvalovatel = dalsiSchvalovatel;
    }
    @Override
    public void posuditPoziadavku(String poziadavka) {
        if(poziadavka == "DOVOLENKA") {
            System.out.println(poziadavka + " - " + meno + " schvalil poziadavku");
        }
        else {
            super.posuditPoziadavku(poziadavka);
        }
    }
}

Riaditel.java

package designpatterns;
public class Riaditel extends SchvalovatelPoziadavky {
    public Riaditel() {
        super("riaditel");
    }
    @Override
    public void nastavitDalsiehoSchvalovatela(SchvalovatelPoziadavky dalsiSchvalovatel) {
        this.dalsiSchvalovatel = dalsiSchvalovatel;
    }
    @Override
    public void posuditPoziadavku(String poziadavka) {
        if(poziadavka == "ZVYSENIE_PLATU") {
            System.out.println(poziadavka + " - " + meno + " schvalil poziadavku");
        }
        else {
            super.posuditPoziadavku(poziadavka);
        }
    }
}

Zamestnanec, Veduci, Riaditel are specific classes representing individual employees. Each of them can approve certain types of requests, but if they are not authorized for some of them, they will pass them on to the next approver in the chain.

Main.java

import designpatterns.Riaditel;
import designpatterns.SchvalovatelPoziadavky;
import designpatterns.Veduci;
import designpatterns.Zamestnanec;

public class Main {
    public static void main(String[] args) {
        // Clanky retaze
        SchvalovatelPoziadavky zamestnanec = new Zamestnanec();
        SchvalovatelPoziadavky veduci = new Veduci();
        SchvalovatelPoziadavky riaditel = new Riaditel();
        // Vytvorenie retaze zodpovednosti
        zamestnanec.nastavitDalsiehoSchvalovatela(veduci);
        veduci.nastavitDalsiehoSchvalovatela(riaditel);
        // Posudenie poziadaviek
        zamestnanec.posuditPoziadavku("NAVSTEVA_LEKARA");
        zamestnanec.posuditPoziadavku("DOVOLENKA");
        zamestnanec.posuditPoziadavku("ZVYSENIE_PLATU");
        zamestnanec.posuditPoziadavku("FIREMNE_AUTO");
    }
}

In the main method, we create a chain of responsibility, create a hierarchy of individual employees, and then consider the various requirements. Each employee will attempt to approve the request. If he cannot approve it, he delegates it to the next approver in the chain.

In the main method, we create a chain of responsibility, create a hierarchy of individual employees, and then consider the various requirements.
The output of this example.

Summary

The Chain of Responsibility design pattern is used in software design when we need to achieve a flexible way of processing requests, not wanting to create a rigid link between the sender and the processor of the request and passing them to a chain of objects for processing.

We have prepared the files with the above example in the form of code that you can run directly in Java. Download the Java Chain of Responsibility code here.

If you’re a Java developer looking for work, check out our employee benefits and respond to our job offers.

About the author

Jozef Wagner

Java Developer Senior

Viac ako 10 rokov programujem v Jave, momentálne pracujem v msg life Slovakia ako Java programátor senior a pomáham zákazníkom implementovať ich požiadavky do poistného softvéru Life Factory. Vo voľnom čase si rád oddýchnem v lese, prípadne si zahrám nejakú dobrú počítačovú hru.

Let us know about you