Chain of Responsibility
- concept
- Example: Business Scenario 1
- Example: Business Scenario 2
Concept
The Chain of Responsibility Pattern (Chain of Responsibility Pattern) is a behavioral design pattern used to continuously pass a task to multiple processors until it is processed. In Swift, you can implement the Chain of Responsibility pattern using classes.
Example: Business Scenario 1
We can implement a chain of responsibility for processing sales orders, with the following three handlers:
- Sales Manager (SalesManager): Process orders with an order amount ranging from 0 to 1000.
- Finance Department (FinanceDepartment): Process orders with an order amount ranging from 1000 to 5000.
- General Manager: Handle orders with an order amount exceeding 5,000.
Here’s an implementation of the Chain of Responsibility pattern in Swift:
protocol OrderHandler {<!-- --> var next: OrderHandler? {<!-- -->get set} func handleOrder(amount: Double) } class SalesManager: OrderHandler {<!-- --> var next: OrderHandler? func handleOrder(amount: Double) {<!-- --> if amount < 100 {<!-- --> print("Small staff can already process goods worth \(amount)") } else {<!-- --> next?. handleOrder(amount: amount) } } } class FinanceDepartment: OrderHandler {<!-- --> var next: OrderHandler? func handleOrder(amount: Double) {<!-- --> if amount < 1000 {<!-- --> print("The chief financial officer can already handle goods worth \(amount)") } else {<!-- --> next?. handleOrder(amount: amount) } } } class GeneralManager: OrderHandler {<!-- --> var next: OrderHandler? func handleOrder(amount: Double) {<!-- --> if amount < 10000 {<!-- --> print("The general manager can already process goods worth \(amount)") } else {<!-- --> print("No one can handle this item") } } }
Call method
let salesManager = SalesManager() let financeDepartment = FinanceDepartment() let generalManager = GeneralManager() salesManager.next = financeDepartment financeDepartment. next = generalManager generalManager.next = nil financeDepartment. handleOrder(amount: 100.0) financeDepartment. handleOrder(amount: 20000.0)
In the above code, we define an OrderHandler protocol, which contains a handleOrder(amount:) method and an optional attribute next, which is used to build the chain of responsibility. For each order, each handler on the chain of responsibility can be called one by one until the order is processed.
The client operation is as follows:
- Create the SalesManager, FinanceDepartment, and GeneralManager objects and set up the next handler.
- Call the sales manager’s method to process the order.
- According to the order amount, the processors on the chain of responsibility are called one by one until a processor capable of processing the order is found.
Example: Business Scenario 2
Take the example of handling user login as an example
We will create a user login process based on the Chain of Responsibility pattern, which involves the following steps:
- Determine whether the username exists.
- Determine whether the user password is correct.
- Whether two-step verification or two-step verification is enabled.
- Whether all security checks have passed, allowing the user to log in.
If a step does not complete successfully, subsequent steps will not be executed.
Implement as follows:
// chain of responsibility for handling user requests protocol LoginHandler {<!-- --> var next: LoginHandler? {<!-- --> get set } func handle(request: LoginRequest) } // User login request struct LoginRequest {<!-- --> let username: String let password: String var isTwoFactorAuthEnabled: Bool = false var isSecurityCheckPassed: Bool = false } // Processor to determine whether the username exists class CheckUsernameHandler: LoginHandler {<!-- --> var next: LoginHandler? func handle(request: LoginRequest) {<!-- --> if request.username.count == 0 {<!-- --> print("Username cannot be empty") } else {<!-- --> next?.handle(request: request) } } } // Processor to determine whether the user password is correct class CheckPasswordHandler: LoginHandler {<!-- --> var next: LoginHandler? func handle(request: LoginRequest) {<!-- --> if request.password.count == 0 {<!-- --> print("Password cannot be empty") } else {<!-- --> next?.handle(request: request) } } } // Two-step verification or two-step verification handler class TwoFactorAuthHandler: LoginHandler {<!-- --> var next: LoginHandler? func handle(request: LoginRequest) {<!-- --> if request.isTwoFactorAuthEnabled {<!-- --> print("Please pass double verification or two-step verification") } else {<!-- --> next?.handle(request: request) } } } // safety detection handler class SecurityCheckHandler: LoginHandler {<!-- --> var next: LoginHandler? func handle(request: LoginRequest) {<!-- --> if request.isSecurityCheckPassed {<!-- --> print("Successful login") } else {<!-- --> print("Security check failed, please contact administrator") } } }
Call method
let checkUsernameHandler = CheckUsernameHandler() let checkPasswordHandler = CheckPasswordHandler() let twoFactorAuthHandler = TwoFactorAuthHandler() let securityCheckHandler = SecurityCheckHandler() checkUsernameHandler.next = checkPasswordHandler checkPasswordHandler.next = twoFactorAuthHandler twoFactorAuthHandler. next = securityCheckHandler let request1 = LoginRequest(username: "test", password: "", isTwoFactorAuthEnabled: false, isSecurityCheckPassed: false) checkUsernameHandler.handle(request: request1) let request2 = LoginRequest(username: "test", password: "test123", isTwoFactorAuthEnabled: true, isSecurityCheckPassed: false) checkUsernameHandler.handle(request: request2) let request3 = LoginRequest(username: "test", password: "test123", isTwoFactorAuthEnabled: false, isSecurityCheckPassed: true) checkUsernameHandler. handle(request: request3)
In the above code, we first defined the LoginHandler chain-of-responsibility pattern, and then added four handlers in succession to check username, password, double-authentication or two-step verification, and security checks. Stops the chain of responsibility if the given login request fails any of the items.
The sample code for the client call is as follows:
- Create a LoginRequest object and call the handle(request:) method after creating the CheckUsernameHandler processor to start the chain of responsibility process.
- Each handler in the chain of responsibility is called one by one until one is found that can handle the request.
- If none of the items are passed, the chain of responsibility is stopped.
The output is as follows:
password can not be blank
Please pass two-step verification or two-step verification
login successful
This example simply demonstrates how to use the Chain of Responsibility pattern to handle processes in Swift.