Chain of Responsibility Design Pattern in Swift

1. Definition

The Chain of Responsibility Design Pattern provides a way to process a request through a series of handlers or processing objects. Each of these handlers decides either to process the request or to pass it along the chain. This creates a decoupled system where handlers can be added or removed without affecting other handlers in the chain.

2. Problem Statement

Imagine a scenario where an application has multiple levels of authentication checks or validation processes. Implementing all these checks in one monolithic block makes the system rigid, hard to maintain, and violates the Single Responsibility Principle.

3. Solution

Using the Chain of Responsibility pattern, you can decouple the handlers from each other and organize them into a chain. Each handler decides whether to stop the chain and handle the request or to pass it further down the chain.

4. Real-World Use Cases

1. Event handling systems in GUI libraries where events can be processed by multiple listeners.

2. Middleware in web frameworks that handles requests through a series of processing units.

3. Workflow systems where a task moves through a series of steps or processes.

5. Implementation Steps

1. Define a handler interface which declares a method for processing requests and setting the next handler in the chain.

2. Create concrete handlers implementing the handler interface.

3. In the client, link these handlers to form a chain.

6. Implementation in Swift Programming

// 1. Handler interface
protocol Handler {
    var next: Handler? { get set }
    func handle(request: String) -> String?
}
// 2. Concrete Handlers
class AuthenticationHandler: Handler {
    var next: Handler?
    func handle(request: String) -> String? {
        if request == "Authentication" {
            return "AuthenticationHandler: Handling the request."
        }
        return next?.handle(request: request)
    }
}
class ValidationHandler: Handler {
    var next: Handler?
    func handle(request: String) -> String? {
        if request == "Validation" {
            return "ValidationHandler: Handling the request."
        }
        return next?.handle(request: request)
    }
}
// Client Code
let authHandler = AuthenticationHandler()
let validationHandler = ValidationHandler()
authHandler.next = validationHandler
func clientCode(handler: Handler, request: String) {
    print(handler.handle(request: request) ?? "Request not handled")
}
clientCode(handler: authHandler, request: "Authentication")
clientCode(handler: authHandler, request: "Validation")

Output:

AuthenticationHandler: Handling the request.
ValidationHandler: Handling the request.

Explanation:

1. Handler interface provides a blueprint for creating linked objects in the chain.

2. Concrete handlers like AuthenticationHandler and ValidationHandler decide on request processing.

3. In the client code, handlers are linked to form a chain. A request is passed to the first handler, which either handles it or forwards it down the chain.

7. When to use?

Use the Chain of Responsibility pattern when:

1. You want to decouple a sender from receivers by allowing multiple objects to handle the request independently.

2. The set of objects that can handle a request should be specified dynamically.

3. The request needs to be processed by several handlers in a particular order.


Comments