Essential Design Patterns -An Easy Explanation through Real-World Examples - Part 3: Chain of Responsibility

Photo by RetroSupply on Unsplash

Essential Design Patterns -An Easy Explanation through Real-World Examples - Part 3: Chain of Responsibility

Welcome! to the third part of the series on Object-Oriented Design Patterns through Python. Read the second part here. In this post, we will discuss the next important design pattern: the Chain of Responsibility pattern*.*

Chain of Responsibility

The Chain of Responsibility pattern can be classified under behavioral design pattern which concern about identifying common communication patterns between objects and realizing these patterns.

The Chain of Responsibility pattern allows you to chain together a series of handlers to process a request. Each handler in the chain has the opportunity to process the request, and if it can't, it passes the request on to the next handler in the chain.

Real-World Use Case

  • In a request-response system, it is often necessary to execute a series of middleware components that perform specific tasks in a sequential manner. The Chain of Responsibility pattern can be used to design the middleware pipeline, where each component has the ability to process the request or pass it along to the next component in the chain. This approach offers flexibility and extensibility, allowing new middleware components to be added or existing ones to be modified without affecting the overall structure of the system.

  • In a logging and error handling system, different types or levels of errors may occur, and each error needs to be processed and reported appropriately. The Chain of Responsibility pattern can be used to create a chain of error handlers, where each handler can handle a specific type or level of error and pass it to the next handler in the chain if necessary.

Now, let's dive into implementing a middleware scenario using the Chain of Responsibility design pattern.

Implementation

class Request:
    def __init__(self, data):
        self.data = data


class Middleware:
    def __init__(self, successor=None):
        self.successor = successor

    def process_request(self, request):
        pass


class AuthenticationMiddleware(Middleware):
    def process_request(self, request):
        # Perform authentication logic here
        print('AuthenticationMiddleware: Processing request')
        if self.successor:
            self.successor.process_request(request)


class ValidationMiddleware(Middleware):
    def process_request(self, request):
        # Perform validation logic here
        print('ValidationMiddleware: Processing request')
        if self.successor:
            self.successor.process_request(request)


class LoggingMiddleware(Middleware):
    def process_request(self, request):
        # Perform logging logic here
        print('LoggingMiddleware: Processing request')
        if self.successor:
            self.successor.process_request(request)


# Usage example
def func():
    # Create the chain of middleware components
    authentication_middleware = AuthenticationMiddleware()
    validation_middleware = ValidationMiddleware()
    logging_middleware = LoggingMiddleware()

    authentication_middleware.successor = validation_middleware
    validation_middleware.successor = logging_middleware

    # Create a sample request
    request = Request('Sample data')

    # Process the request through the middleware chain
    authentication_middleware.process_request(request)


if __name__ == '__main__':
    func()

In this example, we have three middleware components (AuthenticationMiddleware, ValidationMiddleware, and LoggingMiddleware) that inherits from the abstract Middleware class. Each middleware component has a process_request method that performs a specific task related to the request processing. After a middleware handles the request, it passes it to the next component in the chain.

That concludes our discussion on the Chain of Responsibility pattern, an important software design pattern. I trust that the information and example provided have been helpful in understanding its concepts and potential applications.