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.