責任鏈模式(Chain of Responsibility Pattern)是一種行為型設計模式,也叫職責鏈模式、命令鏈模式。這種模式為請求建立了一個接收者物件的鏈,允許你將請求沿著處理者鏈進行傳送,每個處理者均可對請求進行處理,或將其傳遞給鏈上的下個處理者。
當程式需要使用不同方式來處理多種類請求,且請求型別和順序不可知,或者當必須按順序執行多個處理時,可以使用責任鏈模式。或者如果所需處理及其順序必須在執行時進行改變,也可以使用該模式。
// AbstractHandler.java 所有處理變成鏈式,可以互動干涉,動態組合 public abstract class AbstractHandler { // 形成職責鏈 private AbstractHandler next; // 建立呼叫鏈,傳入多個handler,按順序形成鏈,返回第一個handler public static AbstractHandler link(AbstractHandler first, AbstractHandler... chain) { AbstractHandler head = first; for (AbstractHandler handler : chain) { head.next = handler; head = handler; } return first; } // 子類需要實現的檢查方法 public abstract boolean check(int uid); // 繼續下一個檢查 protected boolean checkNext(int uid) { if (next == null) { return true; } return next.check(uid); } }
```java // AuthHandler.java 許可權檢查類 public class AuthHandler extends AbstractHandler { // 如果檢查不通過則返回失敗,否則繼續下一個檢查 public boolean check(int uid) { System.out.println(this.getClass().getName() + "::check() [uid = " + uid + "]"); if (uid % 2 == 0) { return false; } return checkNext(uid); } } ``` ```java // RequestHandler.java 請求是否安全合法檢查 public class RequestHandler extends AbstractHandler { // 如果檢查不通過則返回失敗,否則繼續下一個檢查 public boolean check(int uid) { System.out.println(this.getClass().getName() + "::check() [uid = " + uid + "]"); if (uid % 1 != 0) { return false; } return checkNext(uid); } } ``` ```java // UserHandler.java 使用者基本資訊檢查類 public class UserHandler extends AbstractHandler { // 如果檢查不通過則返回失敗,否則繼續下一個檢查 public boolean check(int uid) { System.out.println(this.getClass().getName() + "::check() [uid = " + uid + "]"); if (uid % 3 == 0) { return false; } return checkNext(uid); } } ```
/** * 責任鏈模式核心是打造一個呼叫處理鏈,每個處理鏈都實現抽象類的next方法,從而可以任意組織各種檢查行為。 * 通過改變鏈內的成員或者調動它們的順序,允許動態地新增或者刪除職責,從而實現按需組織。 */ // 可以任意組織職責鏈,先後順序根據需要來 AbstractHandler handler1 = AbstractHandler.link( new RequestHandler(), new UserHandler(), new AuthHandler()); System.out.println("handler1.check(1001)開始"); handler1.check(1001); System.out.println("handler1.check(1002)開始"); handler1.check(1002); // 可以任意組織職責鏈,先後順序根據需要來 AbstractHandler handler2 = AbstractHandler.link( new AuthHandler(), new RequestHandler(), new UserHandler()); System.out.println("handler2.check(1001)開始"); handler2.check(1001); System.out.println("handler2.check(1002)開始"); handler2.check(1002);
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> // 定義通用handler typedef struct Handler { char name[50]; // handler鏈指標 struct Handler *next; // 結構體內部的check_handler函數,供各handler獨立實現 bool (*check_handler)(struct Handler *, int); } Handler; // 建立handler呼叫鏈,逐個建立 Handler *link_handler(Handler *handler, Handler *next); // 兩種建立鏈式hander的方式,功能相同,可以傳入多個引數 Handler *make_handler_chain_count(int lenght, ...); Handler *make_handler_chain(Handler *handler, ...); // 檢查handler通用函數 bool check_handler_start(Handler *handler, int param); // 定義許可權檢查handler typedef struct AuthHandler { char name[50]; Handler *next; bool (*check_handler)(struct Handler *, int); } AuthHandler; // 建立AuthHandler AuthHandler *create_auth_handler(char *name); // 定義請求檢查handler typedef struct RequestHandler { char name[50]; Handler *next; bool (*check_handler)(struct Handler *, int); } RequestHandler; // 建立RequestHandler RequestHandler *create_request_handler(char *name); // 定義使用者檢查handler typedef struct UserHandler { char name[50]; Handler *next; bool (*check_handler)(struct Handler *, int); } UserHandler; // 建立UserHandler UserHandler *create_user_handler(char *name);
// handler.c 基礎事件 #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include "func.h" // 建立呼叫鏈,按順序形成鏈,返回第一個handler Handler *link_handler(Handler *handler, Handler *next) { handler->next = next; return handler; } // 不定引數建立呼叫鏈,第一個引數是handler的數量,後面是多個handler Handler *make_handler_chain_count(int lenght, ...) { va_list args; va_start(args, lenght); // 取出第1個handler Handler *first = va_arg(args, Handler *); Handler *head = first; // 把handler追加到next中,形成鏈,總長度減去第1個 for (int i = 0; i < lenght - 1; i++) { head->next = va_arg(args, Handler *); head = head->next; } va_end(args); return first; } // 不定引數建立呼叫鏈,第一個引數是handler的數量,後面是多個handler,最後一個傳NULL Handler *make_handler_chain(Handler *first, ...) { va_list args; va_start(args, first); Handler *head = first; // 把handler追加到next中,以NULL作為結束符 while (head != NULL) { head->next = va_arg(args, Handler *); head = head->next; } va_end(args); return first; } // 單獨handler檢查開始函數 bool check_handler_start(Handler *handler, int param) { return handler->check_handler(handler, param); }
```c // auth_handler.c 許可權檢查類 #include <string.h> #include <stdio.h> #include <stdlib.h> #include "func.h" /* AuthHandler check函數實現 */ bool auth_handler_check(Handler *handler, int param) { printf("\r\n auth_handler_check: [handler.name = %s param = %d]", handler->name, param); AuthHandler *auth_handler = (AuthHandler *)handler; // 這裡是判斷條件,如果出錯則終止呼叫鏈,返回false if (param % 2 == 0) { printf("\r\n auth_handler_check: error[ %d %s 2 ] == 0", param, "%"); return false; } // 通過next呼叫下一步檢查 if (handler->next != NULL) { return auth_handler->next->check_handler(handler->next, param); } return true; } /* 建立具體處理器的函數 */ AuthHandler *create_auth_handler(char *name) { AuthHandler *handler = (AuthHandler *)malloc(sizeof(AuthHandler)); strncpy(handler->name, name, 50); // 將handler的check_handler函數賦值為指定函數,便於檢查處理 handler->check_handler = &auth_handler_check; handler->next = NULL; return handler; } ``` ```c // request_handler.c 請求是否安全合法檢查 #include <string.h> #include <stdio.h> #include <stdlib.h> #include "func.h" /* RequestHandler check函數實現 */ bool request_handler_check(Handler *handler, int param) { printf("\r\n request_handler_check: [handler.name = %s param = %d]", handler->name, param); RequestHandler *request_handler = (RequestHandler *)handler; // 這裡是判斷條件,如果出錯則終止呼叫鏈,返回false if (param % 5 == 0) { printf("\r\n request_handler_check: error[ %d %s 5 ] == 0", param, "%"); return false; } // 通過next呼叫下一步檢查 if (handler->next != NULL) { return request_handler->next->check_handler(handler->next, param); } return true; } /* 建立具體處理器的函數 */ RequestHandler *create_request_handler(char *name) { RequestHandler *handler = (RequestHandler *)malloc(sizeof(RequestHandler)); strncpy(handler->name, name, 50); // 將handler的check_handler函數賦值為指定函數,便於檢查處理 handler->check_handler = &request_handler_check; handler->next = NULL; return handler; } ``` ```c // user_handler.c 使用者基本資訊檢查類 #include <string.h> #include <stdio.h> #include <stdlib.h> #include "func.h" /* UserHandler check_handler函數實現 */ bool user_handler_check(Handler *handler, int param) { printf("\r\n user_handler_check: [handler.name = %s param = %d]", handler->name, param); UserHandler *user_handler = (UserHandler *)handler; // 這裡是判斷條件,如果出錯則終止呼叫鏈,返回false if (param % 3 == 0) { printf("\r\n user_handler_check: error[ %d %s 3 ] == 0", param, "%"); return false; } // 通過next呼叫下一步檢查 if (handler->next != NULL) { return user_handler->next->check_handler(handler->next, param); } return true; } /* 建立具體處理器的函數 */ UserHandler *create_user_handler(char *name) { UserHandler *handler = (UserHandler *)malloc(sizeof(UserHandler)); strncpy(handler->name, name, 50); // 將handler的check_handler函數賦值為指定函數,便於檢查處理 handler->check_handler = &user_handler_check; handler->next = NULL; return handler; } ```
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include "../src/func.h" int main(void) { /** * 責任鏈模式核心是打造一個呼叫處理鏈,每個處理鏈都實現抽象類的next方法,從而可以任意組織各種檢查行為。 * 通過改變鏈內的成員或者調動它們的順序,允許動態地新增或者刪除職責,從而實現按需組織。 */ // 建立一組hanler RequestHandler *request_handler = create_request_handler("request_handler_01"); UserHandler *user_handler = create_user_handler("user_handler_02"); AuthHandler *auth_handler = create_auth_handler("auth_handler_03"); printf("建立handler:\r\n %s %s %s", request_handler->name, user_handler->name, auth_handler->name); // 將handler逐個連結成職責鏈 link_handler((Handler *)request_handler, (Handler *)user_handler); link_handler((Handler *)user_handler, (Handler *)auth_handler); printf("\r\n建立職責鏈:\r\n"); Handler *handler_cur = (Handler *)request_handler; while (handler_cur != NULL) { printf(" -> %s", handler_cur->name); handler_cur = handler_cur->next; } // 從任意handler開始檢查 // printf("\r\ncheck_handler_start檢查:"); // check_handler_start((Handler *)request_handler, 666); // 從執行handler開始 printf("\r\n開始檢查:"); bool result1 = request_handler->check_handler((Handler *)request_handler, 666); printf("\r\n執行結果: %s \r\n", result1 ? "true" : "false"); /* 釋放記憶體 */ free(handler_cur); free(request_handler); free(auth_handler); free(user_handler); /*** ========分割線============ ***/ printf("\r\n=============\r\n"); /* 建立一組hanler */ RequestHandler *request_handler2 = create_request_handler("request_handler_101"); UserHandler *user_handler2 = create_user_handler("user_handler_102"); AuthHandler *auth_handler2 = create_auth_handler("auth_handler_103"); printf("\r\n建立handler:\r\n %s %s %s", request_handler2->name, user_handler2->name, auth_handler2->name); // 將handler一次性連結為職責鏈,傳入多個handler,第一個引數是數量 Handler *handler2 = make_handler_chain_count(3, auth_handler2, request_handler2, user_handler2); printf("\r\n建立職責鏈:\r\n"); Handler *handler_cur2 = (Handler *)handler2; while (handler_cur2 != NULL) { printf(" -> %s", handler_cur2->name); handler_cur2 = handler_cur2->next; } // 呼叫通用檢查函數開始 printf("\r\n開始檢查:"); bool result2 = check_handler_start(handler2, 777); printf("\r\n執行結果: %s \r\n", result2 ? "true" : "false"); /* 釋放記憶體 */ free(handler_cur2); free(request_handler2); free(auth_handler2); free(user_handler2); /*** ========分割線============ ***/ printf("\r\n=============\r\n"); /* 再建立一組hanler */ RequestHandler *request_handler3 = create_request_handler("request_handler_201"); UserHandler *user_handler3 = create_user_handler("user_handler_202"); AuthHandler *auth_handler3 = create_auth_handler("auth_handler_203"); printf("\r\n建立handler:\r\n %s %s %s", request_handler3->name, user_handler3->name, auth_handler3->name); // 將handler一次性連結為職責鏈,傳入多個handler,最後一個引數是NULL Handler *handler3 = make_handler_chain((Handler *)auth_handler3, user_handler3, request_handler3, NULL); Handler *handler_cur3 = (Handler *)handler3; printf("\r\n建立職責鏈:\r\n"); while (handler_cur3 != NULL) { printf(" -> %s", handler_cur3->name); handler_cur3 = handler_cur3->next; } printf("\r\n開始檢查:"); bool result3 = check_handler_start(handler3, 167); printf("\r\n執行結果: %s \r\n", result3 ? "true" : "false"); /* 釋放記憶體 */ free(handler_cur3); free(request_handler3); free(auth_handler3); free(user_handler3); return 0; }
不同語言實現設計模式:https://github.com/microwind/design-pattern