Open In App

Chain of Responsibility – Python Design Patterns

Last Updated : 06 Jun, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Chain of Responsibility method is Behavioral design pattern and it is the object-oriented version of if … elif … elif … else and make us capable to rearrange the condition-action blocks dynamically at the run-time. It allows us to pass the requests along the chain of handlers. The processing is simple, whenever any handler received the request it has two choices either to process it or pass it to the next handler in the chain. 
This pattern aims to decouple the senders of a request from its receivers by allowing the request to move through chained receivers until it is handled. 
 

chain-of-responsibility-method


 

Problem without using Chain of Responsibility Method


Imagine you are building a simple website that takes input strings and tells about the various properties of the strings such as is the string palindrome? is string upperCase? is string lowerCase? and many other properties too. After the complete planning, you decide that these checks for the input string should be performed sequentially. So, here the problem arises for the developer that he/she has to implement such an application that can decide on run-time which action should be performed next.
 

Solution using Chain of Responsibility Method


Chain of Responsibility Method provides the solution for the above-described problem. It creates a separate Abstract handler which is used to handle the sequential operations which should be performed dynamically. For eg., we create four handlers named as FirstConcreteHandler, SecondConcreteHandler, ThirdConcreteHandler, and Defaulthandler and calls them sequentially from the user class.
 

Python3
class AbstractHandler(object):

    """Parent class of all concrete handlers"""

    def __init__(self, nxt):

        """change or increase the local variable using nxt"""

        self._nxt = nxt

    def handle(self, request):

        """It calls the processRequest through given request"""

        handled = self.processRequest(request)

        """case when it is not handled"""

        if not handled:
            self._nxt.handle(request)

    def processRequest(self, request):

        """throws a NotImplementedError"""

        raise NotImplementedError('First implement it !')


class FirstConcreteHandler(AbstractHandler):

    """Concrete Handler # 1: Child class of AbstractHandler"""

    def processRequest(self, request):

        '''return True if request is handled '''

        if 'a' < request <= 'e':
            print("This is {} handling request '{}'".format(self.__class__.__name__, request))
            return True


class SecondConcreteHandler(AbstractHandler):

    """Concrete Handler # 2: Child class of AbstractHandler"""

    def processRequest(self, request):

        '''return True if the request is handled'''

        if 'e' < request <= 'l':
            print("This is {} handling request '{}'".format(self.__class__.__name__, request))
            return True

class ThirdConcreteHandler(AbstractHandler):

    """Concrete Handler # 3: Child class of AbstractHandler"""

    def processRequest(self, request):

        '''return True if the request is handled'''

        if 'l' < request <= 'z':
            print("This is {} handling request '{}'".format(self.__class__.__name__, request))
            return True

class DefaultHandler(AbstractHandler):

    """Default Handler: child class from AbstractHandler"""

    def processRequest(self, request):

        """Gives the message that the request is not handled and returns true"""

        print("This is {} telling you that request '{}' has no handler right now.".format(self.__class__.__name__,
                                                                                          request))
        return True


class User:

    """User Class"""

    def __init__(self):

        """Provides the sequence of handles for the users"""

        initial = None

        self.handler = FirstConcreteHandler(SecondConcreteHandler(ThirdConcreteHandler(DefaultHandler(initial))))

    def agent(self, user_request):

        """Iterates over each request and sends them to specific handles"""

        for request in user_request:
            self.handler.handle(request)

"""main method"""

if __name__ == "__main__":

    """Create a client object"""
    user = User()

    """Create requests to be processed"""

    string = "GeeksforGeeks"
    requests = list(string)

    """Send the requests one by one, to handlers as per the sequence of handlers defined in the Client class"""
    user.agent(requests)

Output

This is DefaultHandler telling you that request 'G' has no handler right now.
This is FirstConcreteHandler handling request 'e'
This is FirstConcreteHandler handling request 'e'
This is SecondConcreteHandler handling request 'k'
This is ThirdConcreteHandler handling request 's'
This is SecondConcreteHandler handling request 'f'
This is ThirdConcreteHandler handling request 'o'
This is ThirdConcreteHandler handling request 'r'
This is DefaultHandler telling you that request 'G' has no handler right now.
This is FirstConcreteHandler handling request 'e'
This is FirstConcreteHandler handling request 'e'
This is SecondConcreteHandler handling request 'k'
This is ThirdConcreteHandler handling request 's'

Class Diagram

Class Diagram for Chain of Responsibility Method
 

Chain-Of-Responsibility_class_diagram


 

Advantages


 

  • Single Responsibility Principle: It’s easy to decouple the classes here that invoke operations from classes that perform operations.
  • Open/Closed principle: We can introduce the new code classes without breaking th existing client code.
  • Increases Flexibility: While giving the responsibilities to the objects, it increases the flexibility of the code.


 

Disadvantages


 

  • Unassured about request: This method doesn’t provide any assurance whether the object will be received or not.
  • Spotting characteristics: Due to debugging, it becomes difficult task to observe the characteristics of operations.
  • Depreciated System Performance: It might affect the system’s performance due to continuous cycle calls


 

Applicability


 

  • Processing several handlers in order: Chain of responsibility method helps very much when it is required to process several handlers in a particular order because the linking is possible in any order
  • Decoupling requests: This method is generally used when you want to decouple the request’s sender and receiver.
  • Unspecified handlers: When you don’t want to specify handlers in the code, it is always preferred to use the Chain of Responsibility.


Further Read – Chain of Responsibility in Java
 



Previous Article
Next Article

Similar Reads

Chain of Responsibility Method Design Patterns in C++
Chain of responsibility Pattern or Chain of Responsibility Method is a behavioral pattern, which allows an object to send a request to other objects without knowing who is going to handle it. This pattern is frequently used in the chain of multiple objects, where each object either handles the request or passes it on to the next object in the chain
8 min read
Chain of Responsibility Design Pattern
The Chain of Responsibility design pattern is a behavioral design pattern that allows an object to pass a request along a chain of handlers. Each handler in the chain decides either to process the request or to pass it along the chain to the next handler. Important Topics for the Chain of Responsibility Design Pattern What is the Chain of Responsib
9 min read
Difference Between Architectural Style, Architectural Patterns and Design Patterns
Many software professionals think that architectural styles and patterns are the same. Sadly, some of the software developers don’t understand the difference between architectural patterns and design patterns. In this article, we're going to summarize the differences between them. According to MSDN, architectural styles and patterns are the same th
7 min read
Connectivity and Composition Patterns | Design Patterns for Cloud Native Applications
In cloud-native applications, the architectural design becomes a critical aspect, defining the success of the entire solution. Connectivity and composition patterns are fundamental design principles that dictate how different components within a cloud-native application communicate and collaborate. Let's delve deeper into the significance of these
9 min read
Single Responsibility in SOLID Design Principle
SOLID principle is an acronym that stands for 5 key principles in software development: S - Single Responsibility Principle O - Open Closed Principle L - Liskov Substitution PrincipleI - Interface Segregation PrincipleD - Dependency Inversion Principle It has become one of the key principles in modern software development to ensure the code is usin
4 min read
CQRS - Command Query Responsibility Segregation Design Pattern
The Command Query Responsibility Segregation (CQRS) design pattern has emerged as a powerful architectural pattern for building complex and scalable software systems. By separating the responsibilities of reading and writing data, CQRS allows for more flexible and efficient designs, particularly in domains with high-performance and scalability requ
9 min read
Composite Design Pattern | JavaScript Design Patterns
The Composite Design pattern is a way of organizing objects. It helps us handle different objects in a similar way when they are put together to create a structure with parts and wholes. These parts and wholes are like building blocks that can be split into smaller pieces and then put together to make a tree-like structure. The composite design pat
6 min read
Strategy Method Design Pattern | C++ Design Patterns
Strategy Pattern is a behavioral design pattern that defines a family of interchangeable algorithms and allows them to be used interchangeably within a context. This pattern enables the algorithm to be selected at runtime, providing flexibility and promoting code reusability. Important Topics for the Strategy Method in C++ Design Patterns Example o
4 min read
Memento Design Pattern | C++ Design Patterns
Memento Design Pattern is a behavioral design pattern that provides a mechanism for capturing an object's internal state and restoring it to that state at a later time. This pattern is useful when we need to implement features like undo/redo functionality or when we want to save and restore an object's state for various reasons. Important Topics fo
7 min read
What is the Correlation Between System Design and Design Patterns?
System design and design patterns are closely related concepts in software engineering, with design patterns serving as reusable solutions to common design problems encountered during system design. System design and design patterns are interrelated concepts that work together to create robust and well-structured software systems. Important Topics
11 min read