Chain of Responsibility
The Chain of Responsibility is a behavioral design pattern that allows you to pass a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This pattern decouples the sender of a request from its receivers, giving multiple objects the opportunity to handle the request without the sender explicitly knowing which object will handle it.
This pattern is particularly useful when you have multiple objects that can handle a request, but you don’t know beforehand which object is the appropriate one. It promotes loose coupling and allows you to add or remove handlers dynamically without affecting the client. It is often used in scenarios like request processing pipelines, error handling, and document workflow systems.
Usage
- Request Processing Pipelines: Used extensively in web frameworks and server-side applications to process HTTP requests through a series of middleware or filters. Each middleware component can perform a specific task (e.g., authentication, logging, compression) before passing the request to the next.
- Error Handling: A chain of error handlers can be created to progressively attempt to resolve an error. First handlers might attempt simple fixes, while later handlers might escalate the error or log detailed information.
- Workflow Systems: Implementing business workflows where a request needs to be approved or processed by multiple departments or individuals in a specific order.
- GUI Event Handling: In graphical user interfaces, event handling can be structured as a chain of responsibility where each handler checks if it’s responsible for a specific event and handles it accordingly.
Examples
- Node.js Express Middleware: Express.js utilizes the Chain of Responsibility pattern through its middleware stack. Each middleware function receives the request, response, and next function. It can perform operations on the request/response and then call
next()to pass control to the next middleware in the chain. If a middleware doesn’t callnext(), the chain is terminated. - Java Servlet Filters: Java Servlets employ filters that act as interceptors in a chain. A request passes through a series of filters before reaching the servlet. Each filter can modify the request, response, or terminate the chain. This is analogous to Express middleware.
- PHP Symfony Event Dispatcher: Symfony’s event dispatcher component allows you to register listeners to specific events. When an event is dispatched, the dispatcher iterates through the registered listeners, calling each one in turn until a listener stops the propagation of the event.
- Python’s
loggingmodule: The Pythonloggingmodule uses a chain of handlers to process log records. Each handler is responsible for a specific action, such as writing to a file or sending an email. If a handler cannot process a log record, it can pass it to the next handler in the chain.
Specimens
15 implementationsThe Chain of Responsibility pattern allows you to pass a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This decouples the sender of a request from its receivers, providing flexibility in handling different types of requests.
This Dart implementation defines an abstract RequestHandler class with a nextHandler property. Concrete handlers like AuthenticationRequestHandler, AuthorizationRequestHandler, and LoggingRequestHandler implement the handleRequest method, potentially processing the request and then calling nextHandler.handleRequest(request) if they can’t fully handle it. The client initiates the chain with the first handler. It leverages Dart’s type system and optional chaining to maintain a clean, readable, and flexible design – fitting the generally object-oriented style of Dart.
abstract class RequestHandler {
RequestHandler? nextHandler;
void setNext(RequestHandler next) {
nextHandler = next;
}
void handleRequest(String request);
}
class AuthenticationRequestHandler extends RequestHandler {
@override
void handleRequest(String request) {
if (request.startsWith("auth:")) {
print("Authenticating request: ${request.substring(5)}");
} else {
nextHandler?.handleRequest(request);
}
}
}
class AuthorizationRequestHandler extends RequestHandler {
@override
void handleRequest(String request) {
if (request.startsWith("authz:")) {
print("Authorizing request: ${request.substring(6)}");
} else {
nextHandler?.handleRequest(request);
}
}
}
class LoggingRequestHandler extends RequestHandler {
@override
void handleRequest(String request) {
print("Logging request: $request");
nextHandler?.handleRequest(request); // Always passes to the next handler
}
}
void main() {
// Create the chain
AuthenticationRequestHandler authHandler = AuthenticationRequestHandler();
AuthorizationRequestHandler authzHandler = AuthorizationRequestHandler();
LoggingRequestHandler loggerHandler = LoggingRequestHandler();
authHandler.setNext(authzHandler);
authzHandler.setNext(loggerHandler);
// Send requests
authHandler.handleRequest("auth:user123");
authHandler.handleRequest("authz:resource456");
authHandler.handleRequest("general:some data");
}
The Chain of Responsibility is a behavioral pattern that allows an object to pass a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This decouples the sender of a request from its receivers, allowing for flexible and extensible handling of requests.
My Scala implementation uses a linked list to represent the chain of responsibility. Each handler is a function that takes a request and either processes it, returning a result, or passes it on to the next handler using chain.headOption.map(_.apply(request)). The handleRequest function initiates the chain. This approach is idiomatic Scala due to the use of functional composition and immutable data structures (the linked list chain). It avoids mutable state and leverages Scala’s concise syntax for function definitions and application.
trait Request
case class AuthenticationRequest(username: String, password: String) extends Request
case class LoggingRequest(message: String) extends Request
trait Handler {
def handle(request: Request): Option[String]
}
object ChainOfResponsibility {
def handleRequest(request: Request, chain: List[Handler]): Option[String] = {
chain.headOption.flatMap(handler => handler.handle(request))
}
def authenticationHandler(correctPassword: String): Handler = new Handler {
override def handle(request: AuthenticationRequest): Option[String] = {
if (request.password == correctPassword) {
Some("Authentication successful")
} else {
None
}
}
override def handle(request: Request): Option[String] = None
}
def loggingHandler: Handler = new Handler {
override def handle(request: LoggingRequest): Option[String] = {
Some("Logged: " + request.message)
}
override def handle(request: Request): Option[String] = None
}
def main(args: Array[String]): Unit = {
val authChain = authenticationHandler("password123") :: Nil
val fullChain = authenticationHandler("password123") :: loggingHandler :: Nil
val authRequest = AuthenticationRequest("user", "password123")
val logRequest = LoggingRequest("User accessed the system.")
println(handleRequest(authRequest, authChain)) // Some(Authentication successful)
println(handleRequest(logRequest, authChain)) // None
println(handleRequest(authRequest, fullChain)) // Some(Authentication successful)
println(handleRequest(logRequest, fullChain)) // Some(Logged: User accessed the system.)
}
}
The Chain of Responsibility pattern allows a request to be passed along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This decouples the sender of a request from its receivers, enabling flexible assignment of responsibilities to different handlers.
The PHP implementation uses an interface (HandlerInterface) to define a common handleRequest method, which each concrete handler must implement. The handlers maintain a reference to the next handler in the chain. The handleRequest method checks if the current handler can process the request; if not, it forwards the request to the next handler. This example demonstrates handling expense reports with different approval levels based on amount. Using interfaces and composition aligns with modern PHP practices for loose coupling and extensibility.
<?php
/**
* Handler Interface
*/
interface HandlerInterface
{
public function setNext(HandlerInterface $handler): HandlerInterface;
public function handleRequest(Report $report): ?string;
}
/**
* Report class to represent the expense report
*/
class Report
{
public function __construct(public int $amount, public string $description) {}
}
/**
* Abstract Handler Class
*/
abstract class AbstractHandler implements HandlerInterface
{
private ?HandlerInterface $nextHandler = null;
public function setNext(HandlerInterface $handler): HandlerInterface
{
$this->nextHandler = $handler;
return $handler;
}
public function handleRequest(Report $report): ?string
{
if ($this->canHandle($report)) {
return $this->handle($report);
}
return $this->nextHandler ? $this->nextHandler->handleRequest($report) : null;
}
abstract protected function canHandle(Report $report): bool;
abstract protected function handle(Report $report): ?string;
}
/**
* Concrete Handlers
*/
class ManagerHandler extends AbstractHandler
{
protected function canHandle(Report $report): bool
{
return $report->amount <= 500;
}
protected function handle(Report $report): ?string
{
return "Manager approved: " . $report->description . " for $" . $report->amount;
}
}
class DirectorHandler extends AbstractHandler
{
protected function canHandle(Report $report): bool
{
return $report->amount <= 1500;
}
protected function handle(Report $report): ?string
{
return "Director approved: " . $report->description . " for $" . $report->amount;
}
}
class CeoHandler extends AbstractHandler
{
protected function canHandle(Report $report): bool
{
return true;
}
protected function handle(Report $report): ?string
{
return "CEO approved: " . $report->description . " for $" . $report->amount;
}
}
// Usage
$report1 = new Report(300, "Office Supplies");
$report2 = new Report(1000, "Marketing Campaign");
$report3 = new Report(2000, "New Project");
$manager = new ManagerHandler();
$director = new DirectorHandler();
$ceo = new CeoHandler();
$manager->setNext($director)->setNext($ceo);
echo $manager->handleRequest($report1) . PHP_EOL;
echo $manager->handleRequest($report2) . PHP_EOL;
echo $manager->handleRequest($report3) . PHP_EOL;
?>
The Chain of Responsibility pattern is a behavioral design pattern that allows you to pass a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This decouples the sender of a request from its receivers, allowing multiple objects a chance to handle the request.
The Ruby implementation uses a linked list-like structure where each handler has a next_handler attribute. The handle_request method checks if the handler can process the request; if not, it delegates to the next_handler. This leverages Ruby’s flexible message passing and avoids tight coupling. The use of a base Handler class and a clear handle_request interface promotes extensibility and readability, fitting Ruby’s object-oriented nature.
# frozen_string_literal: true
# Handler base class
class Handler
def initialize(next_handler = nil)
@next_handler = next_handler
end
def handle_request(request)
if can_handle?(request)
handle(request)
elsif @next_handler
@next_handler.handle_request(request)
else
"Request cannot be handled."
end
end
private
def can_handle?(request)
raise NotImplementedError, "Subclasses must implement can_handle?"
end
def handle(request)
raise NotImplementedError, "Subclasses must implement handle"
end
end
# Concrete handlers
class ConcreteHandlerA < Handler
def can_handle?(request)
request.type == 'A'
end
def handle(request)
"Handler A processed request #{request.type}"
end
end
class ConcreteHandlerB < Handler
def can_handle?(request)
request.type == 'B'
end
def handle(request)
"Handler B processed request #{request.type}"
end
end
# Request class
class Request
attr_reader :type
def initialize(type)
@type = type
end
end
# Client code
class Client
def initialize(handler)
@handler = handler
end
def send_request(request)
@handler.handle_request(request)
end
end
# Usage Example
handler_b = ConcreteHandlerB.new
handler_a = ConcreteHandlerA.new(handler_b)
client = Client.new(handler_a)
puts client.send_request(Request.new('A'))
puts client.send_request(Request.new('B'))
puts client.send_request(Request.new('C'))
The Chain of Responsibility pattern is a behavioral design pattern that allows you to pass a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This allows you to avoid coupling the sender of a request to its receiver, giving multiple objects a chance to handle the request without explicitly knowing who’s next in line.
The Swift example uses a protocol SupportRequest to define the interface for requests. Concrete handlers (EmailSupport, TicketSupport, ManagerSupport) conform to this protocol and either resolve the request or pass it on. A Chain class manages the linked handlers. This implementation utilizes Swift’s protocol-oriented programming approach and optionals for chaining, making it clean and self-documenting, aligning with Swift’s focus on safety and readability.
// Define the request interface
protocol SupportRequest {
var severity: Int { get }
var message: String { get }
}
// Concrete handlers
class EmailSupport: SupportRequest {
let severity = 1
let message: String
init(message: String) {
self.message = message
}
func handle() -> String? {
if severity == 1 {
return "Email Support: Handling - \(message)"
}
return nil
}
}
class TicketSupport: SupportRequest {
let severity = 2
let message: String
init(message: String) {
self.message = message
}
func handle() -> String? {
if severity == 2 {
return "Ticket Support: Handling - \(message)"
}
return nil
}
}
class ManagerSupport: SupportRequest {
let severity = 3
let message: String
init(message: String) {
self.message = message
}
func handle() -> String? {
if severity == 3 {
return "Manager Support: Handling - \(message)"
}
return nil
}
}
// The Chain
class Chain {
private var handlers: [SupportRequest] = []
func addHandler(handler: SupportRequest) {
handlers.append(handler)
}
func handleRequest(request: SupportRequest) -> String? {
for handler in handlers {
if let result = handler.handle() {
return result
}
}
return nil
}
}
// Client code
let chain = Chain()
chain.addHandler(handler: EmailSupport(message: "Email issue"))
chain.addHandler(handler: TicketSupport(message: "Ticket creation problem"))
chain.addHandler(handler: ManagerSupport(message: "Critical system outage"))
let request1 = EmailSupport(message: "Password reset")
let request2 = TicketSupport(message: "Can't access feature X")
let request3 = ManagerSupport(message: "Server is down!")
if let result1 = chain.handleRequest(request: request1) {
print(result1)
}
if let result2 = chain.handleRequest(request: request2) {
print(result2)
}
if let result3 = chain.handleRequest(request: request3) {
print(result3)
}
The Chain of Responsibility is a behavioral pattern that allows you to pass a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This decouples the sender of a request from its receivers, giving multiple objects the opportunity to handle it without the sender explicitly knowing who’s handling it.
My Kotlin implementation uses an abstract Handler class with a nextHandler property. Concrete handlers (like AuthHandler, LoggingHandler, and BusinessLogicHandler) inherit from this, and either process the request if they can, or call nextHandler?.handle(request) to pass it along. An explicit chain is built in the main function. This approach leverages Kotlin’s concise syntax, class delegation, and nullable types for a clean and type-safe implementation.
abstract class Handler {
protected var nextHandler: Handler? = null
abstract fun handle(request: String): String
fun setNext(handler: Handler): Handler {
nextHandler = handler
return handler
}
}
class AuthHandler : Handler() {
override fun handle(request: String): String {
if (request == "invalid") {
return "Authentication failed"
}
return nextHandler?.handle(request) ?: request
}
}
class LoggingHandler : Handler() {
override fun handle(request: String): String {
println("Logging request: $request")
return nextHandler?.handle(request) ?: request
}
}
class BusinessLogicHandler : Handler() {
override fun handle(request: String): String {
if (request.startsWith("process")) {
return "Business logic processed: $request"
}
return nextHandler?.handle(request) ?: request
}
}
fun main() {
val chain = AuthHandler()
.setNext(LoggingHandler())
.setNext(BusinessLogicHandler())
println(chain.handle("valid request"))
println(chain.handle("invalid"))
println(chain.handle("process data"))
println(chain.handle("other request"))
}
The Chain of Responsibility pattern promotes decoupling the sender of a request from its receivers by passing the request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This allows for flexible request processing without tightly coupling the request to its specific handler.
The Rust implementation uses traits to define the handler interface, with a next field in the struct holding the next handler. The handle method attempts to process the request, and if unsuccessful, recursively calls handle on the next handler. Ownership is handled via Box<dyn Handler> to allow for polymorphism and avoid concrete type coupling in the chain. This approach aligns well with Rust’s ownership and borrow checking system, allowing a clean, type-safe implementation.
trait Handler {
fn handle(&mut self, request: i32) -> Option<String>;
fn set_next(&mut self, next: Box<dyn Handler>);
}
struct ConcreteHandlerA {
next: Option<Box<dyn Handler>>,
}
impl ConcreteHandlerA {
fn new() -> Self {
ConcreteHandlerA { next: None }
}
}
impl Handler for ConcreteHandlerA {
fn handle(&mut self, request: i32) -> Option<String> {
if request <= 10 {
Some("Handler A handled the request".to_string())
} else {
self.next.as_mut().and_then(|next| next.handle(request))
}
}
fn set_next(&mut self, next: Box<dyn Handler>) {
self.next = Some(next);
}
}
struct ConcreteHandlerB {
next: Option<Box<dyn Handler>>,
}
impl ConcreteHandlerB {
fn new() -> Self {
ConcreteHandlerB { next: None }
}
}
impl Handler for ConcreteHandlerB {
fn handle(&mut self, request: i32) -> Option<String> {
if request <= 50 {
Some("Handler B handled the request".to_string())
} else {
self.next.as_mut().and_then(|next| next.handle(request))
}
}
fn set_next(&mut self, next: Box<dyn Handler>) {
self.next = Some(next);
}
}
fn main() {
let mut handler_a = ConcreteHandlerA::new();
let mut handler_b = ConcreteHandlerB::new();
handler_a.set_next(Box::new(handler_b));
let request1 = 5;
let result1 = handler_a.handle(request1);
println!("Request 1: {:?}", result1);
let request2 = 25;
let result2 = handler_a.handle(request2);
println!("Request 2: {:?}", result2);
let request3 = 60;
let result3 = handler_a.handle(request3);
println!("Request 3: {:?}", result3);
}
The Chain of Responsibility pattern allows a request to be passed along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This decouples the sender of a request from its receivers, giving multiple objects the opportunity to handle the request without the explicit sender knowing which object ultimately handled it.
The Go implementation uses interfaces to define the handler and the request. Each concrete handler implements the interface and either processes the request if it can, or recursively calls the next handler in the chain. The chain itself is built by each handler holding a reference to the next. This leverages Go’s interface capabilities and composition effectively, favoring a flexible and extensible design without strict inheritance hierarchies – a very Go-like approach. Error handling is also a core consideration in the demonstration.
// chain_of_responsibility.go
package main
import "fmt"
// Handler interface defines the contract for all handlers.
type Handler interface {
Handle(request string) (string, error)
SetNext(handler Handler)
}
// concreteHandlerA handles requests related to authentication.
type AuthHandler struct {
next Handler
}
func (h *AuthHandler) Handle(request string) (string, error) {
if request == "auth" {
return "Authentication successful", nil
}
return h.next.Handle(request) // Pass to the next handler
}
func (h *AuthHandler) SetNext(handler Handler) {
h.next = handler
}
// concreteHandlerB handles requests related to logging.
type LogHandler struct {
next Handler
}
func (h *LogHandler) Handle(request string) (string, error) {
if request == "log" {
return "Log entry created", nil
}
return h.next.Handle(request)
}
func (h *LogHandler) SetNext(handler Handler) {
h.next = handler
}
// concreteHandlerC handles all other requests.
type DefaultHandler struct{}
func (h *DefaultHandler) Handle(request string) (string, error) {
return "Request cannot be handled", fmt.Errorf("unsupported request: %s", request)
}
func (h *DefaultHandler) SetNext(handler Handler) {
// Default handler doesn't need a next handler. Necessary to satisfy the interface.
}
func main() {
// Build the chain of responsibility
authHandler := &AuthHandler{}
logHandler := &LogHandler{}
defaultHandler := &DefaultHandler{}
authHandler.SetNext(logHandler)
logHandler.SetNext(defaultHandler)
// Make requests
result1, err1 := authHandler.Handle("auth")
fmt.Println("Auth request:", result1, err1)
result2, err2 := authHandler.Handle("log")
fmt.Println("Log request:", result2, err2)
result3, err3 := authHandler.Handle("other")
fmt.Println("Other request:", result3, err3)
}
The Chain of Responsibility pattern is a behavioral design pattern that allows an object to send a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This decouples the sender of a request from its receivers, allowing for flexible and extensible request handling.
My C implementation uses a structure representing a handler with a function pointer for processing and a pointer to the next handler. The handle_request function initiates the chain. Each handler checks if it can handle the request; if not, it passes the request to the next handler. This avoids tight coupling and allows handlers to be added or removed without modifying existing code. C’s function pointers are ideal for implementing this dynamic dispatch.
#include <stdio.h>
#include <stdlib.h>
typedef struct Handler {
int (*handle_request)(struct Request* request);
struct Handler* next;
} Handler;
typedef struct Request {
int data;
} Request;
int handler1_handle(Request* request) {
if (request->data > 0 && request->data <= 10) {
printf("Handler 1 processed request with data: %d\n", request->data);
return 1;
}
return 0;
}
int handler2_handle(Request* request) {
if (request->data > 10 && request->data <= 100) {
printf("Handler 2 processed request with data: %d\n", request->data);
return 1;
}
return 0;
}
int handler3_handle(Request* request) {
if (request->data > 100) {
printf("Handler 3 processed request with data: %d\n", request->data);
return 1;
}
printf("Request could not be handled.\n");
return 0;
}
int main() {
Handler handler1, handler2, handler3;
Request request1, request2, request3, request4;
handler1.handle_request = handler1_handle;
handler2.handle_request = handler2_handle;
handler3.handle_request = handler3_handle;
handler1.next = &handler2;
handler2.next = &handler3;
handler3.next = NULL;
request1.data = 5;
request2.data = 25;
request3.data = 150;
request4.data = 0;
handle_request(&request1);
handle_request(&request2);
handle_request(&request3);
handle_request(&request4);
return 0;
}
int handle_request(Request* request) {
Handler* current = &handler1; // Start the chain with the first handler
while (current != NULL) {
if (current->handle_request(request) == 1) {
return 1; // Request was handled
}
current = current->next; // Move to the next handler
}
return 0; // Request wasn't handled by anyone in the chain
}
The Chain of Responsibility pattern is a behavioral design pattern that allows you to pass a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This decouples the sender of a request from its receivers.
The C++ example defines an abstract Handler class with a setNext and handleRequest method. Concrete handlers (ConcreteHandlerA, ConcreteHandlerB) override handleRequest to process specific requests or pass them on. The Client code creates the chain and sends a request. This implementation leverages inheritance and virtual functions, core concepts in C++ OOP, to achieve polymorphism—a key aspect of the pattern—and follows common C++ naming and class structure conventions, promoting readability and maintainability.
#include <iostream>
#include <string>
class Handler {
public:
virtual ~Handler() = default;
void setNext(Handler* handler) { nextHandler_ = handler; }
virtual void handleRequest(std::string request) {
if (nextHandler_) {
nextHandler_->handleRequest(request);
} else {
std::cout << "End of chain reached. Request not handled: " << request << std::endl;
}
}
protected:
Handler* nextHandler_;
};
class ConcreteHandlerA : public Handler {
public:
void handleRequest(std::string request) override {
if (request == "A") {
std::cout << "ConcreteHandlerA handled request: " << request << std::endl;
} else {
std::cout << "ConcreteHandlerA passed request: " << request << std::endl;
Handler::handleRequest(request);
}
}
};
class ConcreteHandlerB : public Handler {
public:
void handleRequest(std::string request) override {
if (request == "B") {
std::cout << "ConcreteHandlerB handled request: " << request << std::endl;
} else {
std::cout << "ConcreteHandlerB passed request: " << request << std::endl;
Handler::handleRequest(request);
}
}
};
int main() {
ConcreteHandlerA handlerA;
ConcreteHandlerB handlerB;
handlerA.setNext(&handlerB);
handlerA.handleRequest("A");
handlerA.handleRequest("B");
handlerA.handleRequest("C");
return 0;
}
The Chain of Responsibility pattern allows a request to be passed along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This decouples the sender of a request from its specific receivers, allowing multiple objects to potentially handle the request without the sender knowing which one.
This C# implementation uses an abstract Handler class defining the chain structure and a HandleRequest method. Concrete handlers (ConcreteHandlerA, ConcreteHandlerB) either process the request if they can, or pass it on. The client creates and links the handlers, then sends the request to the first handler in the chain. C#’s interface and abstract class capabilities are leveraged for flexibility and extensibility, fitting the object-oriented nature of the language.
// Chain of Responsibility
// https://gist.github.com/your-username/your-gist-id
// Abstract Handler
public abstract class Handler
{
protected Handler _next;
public void SetNext(Handler next)
{
_next = next;
}
public abstract void HandleRequest(string request);
}
// Concrete Handlers
public class ConcreteHandlerA : Handler
{
public override void HandleRequest(string request)
{
if (request == "A")
{
Console.WriteLine("ConcreteHandlerA handling request: " + request);
}
else if (_next != null)
{
_next.HandleRequest(request);
}
else
{
Console.WriteLine("Request not handled.");
}
}
}
public class ConcreteHandlerB : Handler
{
public override void HandleRequest(string request)
{
if (request == "B")
{
Console.WriteLine("ConcreteHandlerB handling request: " + request);
}
else if (_next != null)
{
_next.HandleRequest(request);
}
else
{
Console.WriteLine("Request not handled.");
}
}
}
// Client
public class Client
{
public static void Main(string[] args)
{
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
handlerA.SetNext(handlerB);
handlerA.HandleRequest("A");
handlerA.HandleRequest("B");
handlerA.HandleRequest("C");
}
}
The Chain of Responsibility pattern is a behavioral design pattern that allows you to pass a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This decouples the sender of a request from its receivers, allowing multiple objects to potentially handle the request without the sender knowing which one will ultimately do so.
This TypeScript implementation uses an abstract Handler class with a setNext and handle method. Concrete handlers (AbstractSupportProcessor, EngineerSupportProcessor, and ManagementSupportProcessor) represent different support levels and check if they can handle a given support level. Client creates and configures the chain, then sends requests. TypeScript’s interfaces and abstract classes are well-suited for defining the handler contract, while function pointers (types) for setNext improve flexibility and maintainability. This demonstrates a clean, type-safe approach common in TypeScript projects.
// Handler Interface
interface SupportHandler {
setNext(handler: SupportHandler): SupportHandler;
handleRequest(level: number): string | null;
}
// Abstract Handler
abstract class Handler implements SupportHandler {
private nextHandler: SupportHandler | null = null;
public setNext(handler: SupportHandler): SupportHandler {
this.nextHandler = handler;
return handler;
}
public handleRequest(level: number): string | null {
if (this.canHandle(level)) {
return this.handle();
} else if (this.nextHandler) {
return this.nextHandler.handleRequest(level);
}
return null; // Request not handled
}
protected abstract canHandle(level: number): boolean;
protected abstract handle(): string;
}
// Concrete Handlers
class AbstractSupportProcessor extends Handler {
protected canHandle(level: number): boolean {
return level <= 1;
}
protected handle(): string {
return "Abstract Support is handling the request.";
}
}
class EngineerSupportProcessor extends Handler {
protected canHandle(level: number): boolean {
return level <= 2;
}
protected handle(): string {
return "Engineer Support is handling the request.";
}
}
class ManagementSupportProcessor extends Handler {
protected canHandle(level: number): boolean {
return level > 2;
}
protected handle(): string {
return "Management Support is handling the request.";
}
}
// Client
class Client {
private handler: SupportHandler;
constructor() {
this.handler = new AbstractSupportProcessor();
this.handler.setNext(new EngineerSupportProcessor()).setNext(new ManagementSupportProcessor());
}
public submitRequest(level: number): string | null {
return this.handler.handleRequest(level);
}
}
// Usage
const client = new Client();
console.log(client.submitRequest(0)); // Abstract Support is handling the request.
console.log(client.submitRequest(1)); // Abstract Support is handling the request.
console.log(client.submitRequest(2)); // Engineer Support is handling the request.
console.log(client.submitRequest(3)); // Management Support is handling the request.
console.log(client.submitRequest(4)); // Management Support is handling the request.
The Chain of Responsibility pattern promotes decoupling the sender of a request from its receivers by passing the request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This allows for a flexible system where handlers can be added or removed without affecting the others.
The JavaScript implementation uses objects as handlers, each with a handle method and a next property pointing to the next handler. The handle method checks if it can process the request; if not, it delegates to next. The initial request is passed to the first handler in the chain. This approach leverages JavaScript’s flexible object model and prototypal inheritance (though not explicitly used here, it’s a common functional pattern). It avoids tight coupling and promotes a more modular design.
// Handler interface (implicitly defined through structure)
class Handler {
constructor() {
this.next = null;
}
setNext(handler) {
this.next = handler;
return handler; // For chaining setNext calls
}
handle(request) {
if (this.next) {
return this.next.handle(request);
}
return null; // Request not handled
}
}
// Concrete Handlers
class ConcreteHandler1 extends Handler {
handle(request) {
if (request.type === "type1") {
console.log("ConcreteHandler1 handling request:", request);
return "Handler 1 processed the request";
}
return super.handle(request);
}
}
class ConcreteHandler2 extends Handler {
handle(request) {
if (request.type === "type2") {
console.log("ConcreteHandler2 handling request:", request);
return "Handler 2 processed the request";
}
return super.handle(request);
}
}
class ConcreteHandler3 extends Handler {
handle(request) {
if (request.type === "type3") {
console.log("ConcreteHandler3 handling request:", request);
return "Handler 3 processed the request";
}
return super.handle(request);
}
}
// Client code
const handler1 = new ConcreteHandler1();
const handler2 = new ConcreteHandler2();
const handler3 = new ConcreteHandler3();
handler1.setNext(handler2).setNext(handler3);
const requests = [
{ type: "type1", data: "data1" },
{ type: "type2", data: "data2" },
{ type: "type3", data: "data3" },
{ type: "type4", data: "data4" } // Not handled
];
requests.forEach(request => {
const result = handler1.handle(request);
if(result) {
console.log("Result:", result);
} else {
console.log("Request not handled.");
}
});
The Chain of Responsibility pattern is a behavioral design pattern that allows you to pass a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain. This decouples the sender of a request from its receivers, allowing for flexible and extensible handling of requests.
The Python implementation uses classes to represent handlers, each with a handle method and a reference to the next handler. The handle method checks if the handler can process the request; if not, it passes it on. The client initiates the chain by sending the request to the first handler. This approach is Pythonic due to its use of classes and method dispatch, promoting code organization and extensibility without tight coupling.
from abc import ABC, abstractmethod
class Handler(ABC):
"""
Abstract Handler class. Defines the interface for handling requests
and passing them on to the next handler in the chain.
"""
def __init__(self, successor=None):
self._successor = successor
@abstractmethod
def handle(self, request):
pass
class ConcreteHandlerA(Handler):
"""
Concrete Handler A. Handles requests of type 'A'.
"""
def handle(self, request):
if request == 'A':
print("ConcreteHandlerA handling request 'A'")
elif self._successor:
self._successor.handle(request)
else:
print("Request 'A' reached the end of the chain!")
class ConcreteHandlerB(Handler):
"""
Concrete Handler B. Handles requests of type 'B'.
"""
def handle(self, request):
if request == 'B':
print("ConcreteHandlerB handling request 'B'")
elif self._successor:
self._successor.handle(request)
else:
print("Request 'B' reached the end of the chain!")
class ConcreteHandlerC(Handler):
"""
Concrete Handler C. Handles requests of type 'C'.
"""
def handle(self, request):
if request == 'C':
print("ConcreteHandlerC handling request 'C'")
elif self._successor:
self._successor.handle(request)
else:
print("Request 'C' reached the end of the chain!")
def client_code(handler):
"""
The client code. Sends different requests to the chain.
"""
requests = ['A', 'B', 'C', 'D']
for request in requests:
print(f"Client sending request '{request}'\n")
handler.handle(request)
print("\n")
if __name__ == "__main__":
# Build the chain: A -> B -> C
handler_a = ConcreteHandlerA(ConcreteHandlerB(ConcreteHandlerC()))
# Run the client code
client_code(handler_a)
The Chain of Responsibility pattern creates a chain of objects where each object has a chance to handle a request. If an object can’t handle the request, it passes it on to the next object in the chain. This avoids coupling the sender of a request to its specific receiver.
The Java implementation uses an interface Handler defining a setNext() and handleRequest() method. Concrete handlers (ConcreteHandlerA, ConcreteHandlerB, and DefaultHandler) implement the interface. DefaultHandler acts as the end of the chain, handling requests no other handler could. The client builds the chain and sends the request to the first handler. This approach leverages Java’s interface and class structure for a clear and extensible design, fitting the object-oriented nature of the language.
// Handler interface
interface Handler {
Handler setNext(Handler handler);
void handleRequest(Request request);
}
// Request class
class Request {
private final int value;
public Request(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
// Concrete Handler A
class ConcreteHandlerA implements Handler {
private Handler nextHandler;
@Override
public Handler setNext(Handler handler) {
this.nextHandler = handler;
return this;
}
@Override
public void handleRequest(Request request) {
if (request.getValue() <= 10) {
System.out.println("ConcreteHandlerA handled request: " + request.getValue());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {
System.out.println("Request not handled.");
}
}
}
// Concrete Handler B
class ConcreteHandlerB implements Handler {
private Handler nextHandler;
@Override
public Handler setNext(Handler handler) {
this.nextHandler = handler;
return this;
}
@Override
public void handleRequest(Request request) {
if (request.getValue() > 10 && request.getValue() <= 20) {
System.out.println("ConcreteHandlerB handled request: " + request.getValue());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {
System.out.println("Request not handled.");
}
}
}
// Default Handler (end of chain)
class DefaultHandler implements Handler {
@Override
public Handler setNext(Handler handler) {
return this; // No next handler
}
@Override
public void handleRequest(Request request) {
System.out.println("DefaultHandler handled request: " + request.getValue());
}
}
// Client
public class ChainOfResponsibility {
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
Handler defaultHandler = new DefaultHandler();
handlerA.setNext(handlerB).setNext(defaultHandler);
handlerA.handleRequest(new Request(5));
handlerA.handleRequest(new Request(15));
handlerA.handleRequest(new Request(25));
}
}