A guide to software design patterns
Behavioral Design Pattern: Chain of Responsibility
The chain of responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects.
This simply means that each object in the chain behaves as an object-oriented version of an if-condition. When a request comes in the chain, if it cannot be handled by the first object, it gets passed on to the next object and so forth until it’s handled or rejected if no object can handle it.
Each object contains specific logic on what level or type of request they can handle. Each object must have a way to add the next processing object to the chain. When an object has no next object, that is an indicator that you’ve reached the end of the chain.
Pattern Ideal Usage
This pattern should be used when there is a clear order of escalation or processing. I always find it easier to grasp concepts with a real-world scenario. Let’s use one and see how we would implement it using this pattern.
Let’s say you’re tasked to design a system that approves or rejects incoming surgical request procedures for a hospital. Each one of these requests will have a patient’s information and the needed specialty. If the specialty in the request is supported, then the surgery is approved. If the specialty in the request isn’t supported and there is a next object in the chain, then the request gets passed to the next object, otherwise, it gets rejected. Let’s look at how we would implement this in code.
Implementation
We won’t be doing any validation and assume all values are valid. It’s always up to you to make sure all user input is validated. With that being said, let’s get started.
We need to start by defining the specialties. We’ll create an enum called Specialties. Here’s the code for our enum.
Here’s the code for the enum:
public enum Specialties {
Heart,
Lungs,
Oesophagus,
Chest,
Veins,
Arteries,
Head,
Neck,
Voice,
Ear,
Nose,
Kidney,
Bladder
}Next, we need a request. The request will have a patient’s first and last name and the needed specialty and named SurgicalRequest.
Here’s the code for the request:
public class SurgicalRequest {
private String firstname;
private String lastname;
private Specialties specialty;
public SurgicalRequest(String firstname,
String lastname,
Specialties specialty)
{
this.firstname = firstname;
this.lastname = lastname;
this.specialty = specialty;
}
public String getFirstname() {
return firstname;
}
public Specialties getSpecialty() {
return specialty;
}
public String getLastname() {
return lastname;
}
}A hospital has many surgeons with different specialties as stated earlier. We’ll start with an abstract class named Surgeon.
Here’s the code for the Surgeon Class:
public abstract class Surgeon {
protected Surgeon nextSurgeon;
public void setNext(Surgeon next){
this.nextSurgeon = next;
}
public abstract void operate(SurgicalRequest request);
}Now that we have the base class, we can define surgical procedures before creating our chain. For brevity, we’ll only create three classes for our chain.
Let’s create a class for a vascular surgeon. Here’s the code:
public class VascularSurgeon extends Surgeon {
@Override
public void operate(SurgicalRequest request) {
Specialties specialty = request.getSpecialty();
if (specialty == Specialties.Arteries
|| specialty == Specialties.Veins)
{
System.out.println(
String.format("The %s will operate on %s %s. Request approved",
this.getClass().getSimpleName(),
request.getFirstname(),
request.getLastname())
);
}
else{
if(nextSurgeon != null){
System.out.println(
String.format("%s cannot operate on patient %s %s. Passing request to %s...",
this.getClass().getSimpleName(),
request.getFirstname(),
request.getLastname(),
nextSurgeon.getClass().getSimpleName())
);
nextSurgeon.operate(request);
}
else{
System.out.println(
String.format("Could not find a surgeon who specializes in %s. Request rejected.",
request.getSpecialty()));
}
}
}
}Let’s create another class for a cardiothoracic surgeon. Here’s the code.
public class CardiothoracicSurgeon extends Surgeon {
@Override
public void operate(SurgicalRequest request) {
Specialties specialty = request.getSpecialty();
if (specialty == Specialties.Heart
|| specialty == Specialties.Lungs
|| specialty == Specialties.Chest
|| specialty == Specialties.Oesophagus)
{
System.out.println(
String.format("The %s will operate on %s %s. Request approved",
this.getClass().getSimpleName(),
request.getFirstname(),
request.getLastname())
);
}
else{
if(nextSurgeon != null){
System.out.println(
String.format("%s cannot operate on patient %s %s. Passing request to %s...",
this.getClass().getSimpleName(),
request.getFirstname(),
request.getLastname(),
nextSurgeon.getClass().getSimpleName())
);
nextSurgeon.operate(request);
}
else{
System.out.println(
String.format("Could not find a surgeon who specializes in %s. Request rejected.",
request.getSpecialty()));
}
}
}
}Let’s create just one more class for an Otolaryngology surgeon. Here’s the code:
public class OtolaryngologySurgeon extends Surgeon {
@Override
public void operate(SurgicalRequest request) {
Specialties specialty = request.getSpecialty();
if (specialty == Specialties.Head
|| specialty == Specialties.Neck
|| specialty == Specialties.Voice
|| specialty == Specialties.Ear
|| specialty == Specialties.Nose)
{
System.out.println(
String.format("The %s will operate on %s %s. Request approved",
this.getClass().getSimpleName(),
request.getFirstname(),
request.getLastname())
);
}
else{
if(nextSurgeon != null){
System.out.println(
String.format("%s cannot operate on patient %s %s. Passing request to %s...",
this.getClass().getSimpleName(),
request.getFirstname(),
request.getLastname(),
nextSurgeon.getClass().getSimpleName())
);
nextSurgeon.operate(request);
}
else{
System.out.println(
String.format("Could not find a surgeon who specializes in %s. Request rejected.",
request.getSpecialty()));
}
}
}
}Now that we have our objects, we can create the chain. We’ll create the chain by first creating an object for each type of surgeon, then set the next object in the chain for each object. Then we’ll create two requests. One can be performed by one of the available surgeons and the other cannot. This will help to demonstrate both when a request is approved and rejected by the chain.
Here’s the code in the main method:
public static void main(String[] args) {
OtolaryngologySurgeon otolarynS = new OtolaryngologySurgeon();
VascularSurgeon vacularS = new VascularSurgeon();
CardiothoracicSurgeon cardioS = new CardiothoracicSurgeon();
//chain
otolarynS.setNext(vacularS);
vacularS.setNext(cardioS);
SurgicalRequest heartRequest = new SurgicalRequest(
"Jackie",
"Chan",
Specialties.Heart
);
System.out.println("\n-----heart request-----");
otolarynS.operate(heartRequest);
SurgicalRequest bladderRequest = new SurgicalRequest(
"Jet",
"Lee",
Specialties.Bladder
);
System.out.println("\n-----bladder request-----");
otolarynS.operate(bladderRequest);
}The output looks like this:
-----heart request-----
OtolaryngologySurgeon cannot operate on patient Jackie Chan. Passing request to VascularSurgeon...
VascularSurgeon cannot operate on patient Jackie Chan. Passing request to CardiothoracicSurgeon...
The CardiothoracicSurgeon will operate on Jackie Chan. Request approved-----bladder request-----
OtolaryngologySurgeon cannot operate on patient Jet Lee. Passing request to VascularSurgeon...
VascularSurgeon cannot operate on patient Jet Lee. Passing request to CardiothoracicSurgeon...
Could not find a surgeon who specializes in Bladder. Request rejected.This is a simple implementation of the chain of responsibility pattern in a nutshell. Thank you for making it to the end.
Happy coding.
Previous: Creational Design Pattern: Prototype





