Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
10 views10 pages

SDA Assignment 2

The Chain of Responsibility pattern is a behavioral design pattern that decouples the sender of a request from its receiver by allowing multiple objects to handle the request in a chain. It is useful in scenarios where the handler is not known at compile time and can be determined at runtime, providing flexibility and reducing coupling between objects. The pattern is applicable in various contexts, such as event handling in user interfaces and exception handling in programming, but it can also lead to unhandled requests and debugging complexities.

Uploaded by

alssyedali2002
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views10 pages

SDA Assignment 2

The Chain of Responsibility pattern is a behavioral design pattern that decouples the sender of a request from its receiver by allowing multiple objects to handle the request in a chain. It is useful in scenarios where the handler is not known at compile time and can be determined at runtime, providing flexibility and reducing coupling between objects. The pattern is applicable in various contexts, such as event handling in user interfaces and exception handling in programming, but it can also lead to unhandled requests and debugging complexities.

Uploaded by

alssyedali2002
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 10

1.

Understanding Chain of Responsibility

1.1 Definition:

The Chain of Responsibility pattern is a part of the GoF patterns and is


categorized under the behavioural patterns. It is defined as:

"Avoid coupling the sender of a request to its receiver by giving more than one
object a chance to handle the request. Chain the receiving objects and pass the
request along the chain until an object handles it."

Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma,


Richard Helm, Ralph Johnson and John Vlissides

1.2 Concept

The Chain of Responsibility design pattern separates the sender of a request from
the receiver. This avoids the coupling of the requester and receiver. Further, the
pattern allows a request to be passed along a chain to several different objects
that have an opportunity to handle the request. The sender doesn't need to know
which object handles the request and the object doesn't need to know who sent the
request. There's no coupling between the two.

Some may look at the Chain of Responsibility Pattern and think " this is nothing
but a big switch statement". In some respects it is, but in most it is not. It does
examine a request to determine whether it matches one of several case conditions.
However, while a switch statement is fixed, a Chain of Responsibility has its
successor defined by each concrete handler.Because each concrete handler includes a
method for specifying its own successor, the client defines the order when it
assigns successors through concrete handler objects.
Further, because the client starts the request chain, it can start it anywhere the
developer decides.

Learning PHP Design Patterns By William B. Sanders

You'd naturally think about using the pattern when:

There is more than one object that may handle a request and the handler is known
only at run time.

You want to issue a request to a group of objects without specifying a particular


reciever that will handle the request explicitly.

Pro Objective-C Design Patterns for iOS by Carlo Chung

2. Real-Life Analogy

2.1 Scenario 1
Suppose you are an employee in a company now you give a request of some approval to
your manager if they can approve it , then you can get response from them otherwise
the request is passed to senior manager , if they can approve it , then you can get
response otherwise it goes to next person or level , so here you as an employee is
completely unaware of how your request is getting approved and how multiple people
are handling your request , this is Chain Responsibility Pattern .
https://medium.com/@ngneha090/beginners-guide-to-chain-responsibility-design-
pattern-in-java-e1e0ddac2cb6

2.2 Scenario 2
You’ve just bought and installed a new piece of hardware on your computer. Since
you’re a geek, the computer has several operating systems installed. You try to
boot all of them to see whether the hardware is supported. Windows detects and
enables the hardware automatically. However, your beloved Linux refuses to work
with the new hardware. With a small flicker of hope, you decide to call the tech-
support phone number written on the box.

The first thing you hear is the robotic voice of the autoresponder. It suggests
nine popular solutions to various problems, none of which are relevant to your
case. After a while, the robot connects you to a live operator.

Alas, the operator isn’t able to suggest anything specific either. He keeps quoting
lengthy excerpts from the manual, refusing to listen to your comments. After
hearing the phrase “have you tried turning the computer off and on again?” for the
10th time, you demand to be connected to a proper engineer.

Eventually, the operator passes your call to one of the engineers, who had probably
longed for a live human chat for hours as he sat in his lonely server room in the
dark basement of some office building. The engineer tells you where to download
proper drivers for your new hardware and how to install them on Linux. Finally, the
solution! You end the call, bursting with joy.
https://refactoring.guru/design-patterns/chain-of-responsibility

2.3 Scenario 3

Level 1 Support:
This represents the first point of contact for customer inquiries. Level 1 support
staff handle basic inquiries and provide general assistance. If they cannot resolve
the issue, they escalate it to Level 2 support.
Level 2 Support:
This level consists of more experienced support staff who can handle more complex
issues that Level 1 support cannot resolve. If Level 2 support cannot resolve the
issue, they escalate it to Level 3 support.
Level 3 Support:
This is the highest level of support, consisting of senior or specialized staff who
can handle critical or highly technical issues. If Level 3 support cannot resolve
the issue, they may involve other departments or experts within the organization.

https://www.geeksforgeeks.org/chain-responsibility-design-pattern/#realworld-
analogy-of-the-chain-of-responsibility-design-pattern

3. Applicability/Use Case

3.1 Example
Event propagation in user interfaces: In graphical user interfaces (GUI), events
such as mouse clicks or keyboard inputs often need to be handled by different
components in the UI hierarchy. The Chain of Responsibility pattern can be used to
propagate events up or down the component hierarchy until a suitable handler is
found. For example, a mouse click event can be passed from the child component to
its parent, and then to the parent’s parent, until a component that can handle the
event is encountered.
https://medium.com/@ngneha090/beginners-guide-to-chain-responsibility-design-
pattern-in-java-e1e0ddac2cb6
Use the Chain of Responsibility pattern when your program is expected to process
different kinds of requests in various ways, but the exact types of requests and
their sequences are unknown beforehand.

The pattern lets you link several handlers into one chain and, upon receiving a
request, “ask” each handler whether it can process it. This way all handlers get a
chance to process the request.

Use the pattern when it’s essential to execute several handlers in a particular
order.

Since you can link the handlers in the chain in any order, all requests will get
through the chain exactly as you planned.

Use the CoR pattern when the set of handlers and their order are supposed to
change at runtime.

If you provide setters for a reference field inside the handler classes, you’ll be
able to insert, remove or reorder handlers dynamically.

https://refactoring.guru/design-patterns/chain-of-responsibility

Exception handling: In some programming languages or frameworks, exception handling


can be implemented using a chain of catch blocks. Each catch block handles specific
types of exceptions, and if a particular catch block cannot handle the exception,
it passes it to the next catch block in the chain. This enables more granular and
specialized exception handling based on the type or nature of the exception.

https://medium.com/@ngneha090/beginners-guide-to-chain-responsibility-design-
pattern-in-java-e1e0ddac2cb6

Use Chain of Responsibility when

more than one object may handle a request, and the handler isn't known a priori.
The handler should be ascertained automatically.
you want to issue a request to one of several objects without specifying the
receiver explicitly.
the set of objects that can handle a request should be specified dynamically.

Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma,


Richard Helm, Ralph Johnson and John Vlissides

4. Related SOLID Principles

Single Responsibility Principle (SRP)


Each handler in the chain is responsible for a specific task or decision.
In the ATM Currency Dispenser example, each dispenser is responsible only for
handling its specific denomination.
2. Open/Closed Principle (OCP)
It allows new types of handlers to be added without modifying the existing code.
You can extend the chain by adding new handler classes that implement the same
handler interface
In the above example, new denominations can be added without altering existing
code.
3. Liskov Substitution Principle (LSP)
The Handlers are typically derived from a common handler interface or an abstract
class. It allows any subclass to be substituted for their parent class (i.e., any
specific handler can replace another in the chain).
All dispensers (Rupees500Dispenser, Rupees200Dispenser.....) are interchangeable
and derived from a common abstract class (CurrencyDispenser).
4. Interface Segregation Principle (ISP)
It usually involves a simple interface for handling requests, often with a single
method like handle(). This design ensures that implementing classes (handlers) are
not forced to depend on methods they do not use.
The dispensers use a simple interface that doesn't enforce unnecessary methods and
only has the dispense() method
5. Dependency Inversion Principle (DIP)
The high-level modules (like the client code creating and using the chain) are not
dependent on the low-level modules (the individual handlers). Instead, both depend
on abstractions.
High-level modules (ATMDispenserChain) depend on the CurrencyDispenser abstract
class, not on concrete implementations, aligning with DIP.

https://ujjwalbhardwaj.me/post/object-oriented-design-chain-of-responsibility-
pattern/

4.1 Single Responsibility Principle (SRP)

4.2 Open-Closed Principle (OCP)

4.3 Dependency Inversion Principle (DIP)

5. Advantages

1.Reduced coupling: The pattern frees an object from knowing which other object
handles a request. An object only has to know that a request will be handled
"appropriately". Both the receiver and the sender have no explicit knowledge of
each other and an object in the chain doesn't have to know about the chain's
structure.

As a result, Chain of Responsibility can simplify object interconnections. Instead


of objects maintaining references to all candidate receivers, they keep a single
reference to their successor.
Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma,
Richard Helm, Ralph Johnson and John Vlissides

2. Added flexibility in assigning responsibilities to objects: Chain of


Responsibility gives you added flexibility in distributing responsibilities among
objects. You can add or change responsibilities for handling a request by adding to
or otherwise changing the chain at run time. Design Patterns: Elements of Reusable
Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson and John
Vlissides

3. Any object can send the request to the objects that handle it, and the objects
that handle a request can be changed so that more or different objects can be
incorporated to deal with requests. So, changes can be made in both the requester
and request handlers without disrupting a larger system. Learning PHP Design
Patterns By William B. Sanders
Decoupling of Objects: The pattern makes enables sending a request to a series of
possible recipients without having to worry about which object will handle it in
the end. This lessens the reliance between items.
Flexibility and Extensibility: New handlers can be easily added or existing ones
can be modified without affecting the client code. This promotes flexibility and
extensibility within the system.
Dynamic Order of Handling: The sequence and order of handling requests can be
changed dynamically during runtime, which allows adjustment of the processing logic
as per the requirements.
Simplified Object Interactions: It simplifies the interaction between the sender
and receiver objects, as the sender does not need to know about the processing
logic.
Enhanced Maintainability: Each handler performs a specific type of processing,
which making maintaining and modifying the individual components easier without
impacting the overall system.

https://www.geeksforgeeks.org/chain-of-responsibility-method-design-patterns-in-c/

6. Disadvantages

1. Receipt isn't guaranteed: Since a request has no explicit receiver, there's no


guarantee it'll be handled- the request can fall off the end of the chain without
ever being handled. A request can also go unhandled when the chain is not
configured properly.

Can be hard to observe and debug at runtime. Head First Design Patterns by Eric
Freeman and Elisabeth Robson

Possible Unhandled Requests: The chain should be implemented correctly otherwise


there is a chance that some requests might not get handled at all, which leads to
unexpected behavior in the application.
Performance Overhead: The request will go through several handlers in the chain if
it is lengthy and complicated, which could cause performance overhead. The
processing logic of each handler has an effect on the system’s overall performance.
Complexity in Debugging: The fact that the chain has several handlers can make
debugging more difficult. Tracking the progression of a request and determining
which handler is in charge of handling it can be difficult.
Runtime Configuration Overhead: It may become more difficult to manage and maintain
the chain of responsibility if the chain is dynamically modified at runtime.

https://www.geeksforgeeks.org/chain-of-responsibility-method-design-patterns-in-c/

7. Code Walkthrough

7.1 Code in Java

public abstract class RequestHandler {


String name;
RequestHandler nextHandler;
private RequestHandler(){

}
public RequestHandler(String name){
this.name=name;
}
abstract void setNext(RequestHandler nextHandler);

void approve (int id)


{
if(this.nextHandler != null)
this.nextHandler.approve(id);
else
System.out.println("request cannot be approved");
}
}

public class Manager extends RequestHandler{


public Manager(){
super("manager");
}
@Override
void setNext(RequestHandler nextHandler){
this.nextHandler=nextHandler;
}
@Override
void approve(int id){
if(id>=1 && id<=20)
{
System.out.println("Request Approved");
}
else{
super.approve(id);
}
}
}

public class SeniorManager extends RequestHandler{


public SeniorManager(){
super("Senior manager");
}
@Override
void setNext(RequestHandler nextHandler){
this.nextHandler=nextHandler;
}
@Override
void approve(int id){
if(id>=21 && id<=40)
{
System.out.println("Request Approved");
}
else{
super.approve(id);
}
}
}

public class Director extends RequestHandler{


public Director(){
super("Director");
}
@Override
void setNext(RequestHandler nextHandler){
this.nextHandler=nextHandler;
}
@Override
void approve(int id){
if(id>=41 && id<=80)
{
System.out.println("Request Approved");
}
else{
super.approve(id);
}
}
}

public class Main {


public static void main(String[] args) {
RequestHandler manager=new Manager();
RequestHandler seniorManager=new SeniorManager();
RequestHandler director=new Director();
manager.setNext(seniorManager);
seniorManager.setNext(director);
manager.approve(19);
manager.approve(90);
}
}

https://medium.com/@ngneha090/beginners-guide-to-chain-responsibility-design-
pattern-in-java-e1e0ddac2cb6

public abstract class Logger {


public static int OUTPUTINFO=1;
public static int ERRORINFO=2;
public static int DEBUGINFO=3;
protected int levels;
protected Logger nextLevelLogger;
public void setNextLevelLogger(Logger nextLevelLogger) {
this.nextLevelLogger = nextLevelLogger;
}
public void logMessage(int levels, String msg){
if(this.levels<=levels){
displayLogInfo(msg);
}
if (nextLevelLogger!=null) {
nextLevelLogger.logMessage(levels, msg);
}
}
protected abstract void displayLogInfo(String msg);
}

public class ConsoleBasedLogger extends Logger {


public ConsoleBasedLogger(int levels) {
this.levels=levels;
}
@Override
protected void displayLogInfo(String msg) {
System.out.println("CONSOLE LOGGER INFO: "+msg);
}
}

public class DebugBasedLogger extends Logger {


public DebugBasedLogger(int levels) {
this.levels=levels;
}
@Override
protected void displayLogInfo(String msg) {
System.out.println("DEBUG LOGGER INFO: "+msg);
}
}// End of the DebugBasedLogger class.

public class ErrorBasedLogger extends Logger {


public ErrorBasedLogger(int levels) {
this.levels=levels;
}
@Override
protected void displayLogInfo(String msg) {
System.out.println("ERROR LOGGER INFO: "+msg);
}
}// End of the ErrorBasedLogger class.

public class ChainofResponsibilityClient {


private static Logger doChaining(){
Logger consoleLogger = new ConsoleBasedLogger(Logger.OUTPUTINFO);

Logger errorLogger = new ErrorBasedLogger(Logger.ERRORINFO);


consoleLogger.setNextLevelLogger(errorLogger);

Logger debugLogger = new DebugBasedLogger(Logger.DEBUGINFO);


errorLogger.setNextLevelLogger(debugLogger);

return consoleLogger;
}
public static void main(String args[]){
Logger chainLogger= doChaining();

chainLogger.logMessage(Logger.OUTPUTINFO, "Enter the sequence of


values ");
chainLogger.logMessage(Logger.ERRORINFO, "An error is occured now");
chainLogger.logMessage(Logger.DEBUGINFO, "This was the error now
debugging is compeled");
}
}

https://www.javatpoint.com/chain-of-responsibility-pattern

7.2 Code in C++

/**
* The Handler interface declares a method for building the chain of handlers.
* It also declares a method for executing a request.
*/
class Handler {
public:
virtual Handler *SetNext(Handler *handler) = 0;
virtual std::string Handle(std::string request) = 0;
};
/**
* The default chaining behavior can be implemented inside a base handler class.
*/
class AbstractHandler : public Handler {
/**
* @var Handler
*/
private:
Handler *next_handler_;

public:
AbstractHandler() : next_handler_(nullptr) {
}
Handler *SetNext(Handler *handler) override {
this->next_handler_ = handler;
// Returning a handler from here will let us link handlers in a convenient
// way like this:
// $monkey->setNext($squirrel)->setNext($dog);
return handler;
}
std::string Handle(std::string request) override {
if (this->next_handler_) {
return this->next_handler_->Handle(request);
}

return {};
}
};
/**
* All Concrete Handlers either handle a request or pass it to the next handler
* in the chain.
*/
class MonkeyHandler : public AbstractHandler {
public:
std::string Handle(std::string request) override {
if (request == "Banana") {
return "Monkey: I'll eat the " + request + ".\n";
} else {
return AbstractHandler::Handle(request);
}
}
};
class SquirrelHandler : public AbstractHandler {
public:
std::string Handle(std::string request) override {
if (request == "Nut") {
return "Squirrel: I'll eat the " + request + ".\n";
} else {
return AbstractHandler::Handle(request);
}
}
};
class DogHandler : public AbstractHandler {
public:
std::string Handle(std::string request) override {
if (request == "MeatBall") {
return "Dog: I'll eat the " + request + ".\n";
} else {
return AbstractHandler::Handle(request);
}
}
};
/**
* The client code is usually suited to work with a single handler. In most
* cases, it is not even aware that the handler is part of a chain.
*/
void ClientCode(Handler &handler) {
std::vector<std::string> food = {"Nut", "Banana", "Cup of coffee"};
for (const std::string &f : food) {
std::cout << "Client: Who wants a " << f << "?\n";
const std::string result = handler.Handle(f);
if (!result.empty()) {
std::cout << " " << result;
} else {
std::cout << " " << f << " was left untouched.\n";
}
}
}
/**
* The other part of the client code constructs the actual chain.
*/
int main() {
MonkeyHandler *monkey = new MonkeyHandler;
SquirrelHandler *squirrel = new SquirrelHandler;
DogHandler *dog = new DogHandler;
monkey->SetNext(squirrel)->SetNext(dog);

/**
* The client should be able to send a request to any handler, not just the
* first one in the chain.
*/
std::cout << "Chain: Monkey > Squirrel > Dog\n\n";
ClientCode(*monkey);
std::cout << "\n";
std::cout << "Subchain: Squirrel > Dog\n\n";
ClientCode(*squirrel);

delete monkey;
delete squirrel;
delete dog;

return 0;
}
https://refactoring.guru/design-patterns/chain-of-responsibility/cpp/example

8. References

You might also like