【责任链设计模式详解】C/Java/JS/Go/Python/TS不同语言实现
简介
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,也叫职责链模式、命令链模式。这种模式为请求创建了一个接收者对象的链,允许你将请求沿着处理者链进行发送,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。
当程序需要使用不同方式来处理多种类请求,且请求类型和顺序不可知,或者当必须按顺序执行多个处理时,可以使用责任链模式。或者如果所需处理及其顺序必须在运行时进行改变,也可以使用该模式。
作用
- 避免请求发送者与接收者耦合在一起,客户只需要将请求发送到链上,而无须关心请求的处理细节和请求的传递。
- 通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
实现步骤
- 创建一个抽象处理器类,用来供处理器继承。
- 抽象处理器类可将各子类按任意组织为链式,以便调用。
- 创建多个互不干涉的处理器,实现抽象类的next方法,以便不断执行链式检查。
UML
Java代码
抽象事件处理类
// 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);
C语言代码
func.h 头文件函数
#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
【责任链设计模式详解】C/Java/JS/Go/Python/TS不同语言实现的更多相关文章
- [ 转载 ] Java开发中的23种设计模式详解(转)
Java开发中的23种设计模式详解(转) 设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类 ...
- android java 设计模式详解 Demo
android java 设计模式详解 最近看了一篇设计模式的文章,深得体会,在此基础我将每种设计模式的案例都写成Demo的形式,方便读者研究学习, 首先先将文章分享给大家: 设计模式(Design ...
- Java温故而知新(5)设计模式详解(23种)
一.设计模式的理解 刚开始“不懂”为什么要把很简单的东西搞得那么复杂.后来随着软件开发经验的增加才开始明白我所看到的“复杂”恰恰就是设计模式的精髓所在,我所理解的“简单”就是一把钥匙开一把锁的模式,目 ...
- JAVA设计模式简介及六种常见设计模式详解
一.什么是设计模式 ...
- Java设计模式之责任链设计模式
职责链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将所有处理对象连成一条链,并沿着这条链传递请求,直到有一个对象处理 ...
- 最详尽的 JS 原型与原型链终极详解,没有「可能是」。(一)
最详尽的 JS 原型与原型链终极详解,没有「可能是」.(一) 第二篇已更新,点击进入第三篇已更新,点击进入
- java filter过滤器及责任链设计模式
什么是Filter? Filter属于sevlet规范,翻译为过滤器. Filter在web开发中有什么作用? 案例一:一个web站点只有用户登录才能继续访问该站点的资源,那么需要用户每次访问都判断是 ...
- Java中的责任链设计模式,太牛了!
责任链设计模式的思想很简单,就是按照链的顺序执行一个个处理方法,链上的每一个任务都持有它后面那个任务的对象引用,以方便自己这段执行完成之后,调用其后面的处理逻辑. 下面是一个责任链设计模式的简单的实现 ...
- Javascript设计模式详解
Javascript常用的设计模式详解 阅读目录 一:理解工厂模式 二:理解单体模式 三:理解模块模式 四:理解代理模式 五:理解职责链模式 六:命令模式的理解: 七:模板方法模式 八:理解javas ...
- Javascript常用的设计模式详解
Javascript常用的设计模式详解 阅读目录 一:理解工厂模式 二:理解单体模式 三:理解模块模式 四:理解代理模式 五:理解职责链模式 六:命令模式的理解: 七:模板方法模式 八:理解javas ...
随机推荐
- Spectracom 默认口令
网络空间搜索: FoFa 找到页面: 默认口令 在github上去找 登陆成功 End!!!
- OPENSSL 生成RSA公钥、私钥和证书
在命令窗口执行下列操作. 1)生成RSA私钥: openssl genrsa -out rsa_private_key.pem 2048 生成内容: -----BEGIN RSA PRIVATE KE ...
- 使用SharpCompress压缩文件后把压缩的文件流传给前端
1 SharpCompress版本 0.30.1 2 应用场景:前端传递某个标识符,如Id,查询和该Id相关联的文件,并把文件压缩,最后返回给前端.适用于压缩多个体积较小的文件,如果文件体系过大,可能 ...
- python操作 linux连接wifi,查看wifi连接状态方法
Python连接Ubuntu 环境 wifi流程 1.获取网络接口列表 通过wifi_net.py 的query_net_cards方法获取终端物理网络接口列表及IP信息: 获取物理网络接口列表: ...
- Latex Algorithm 语法错误导致无法编译
遇到了几种情况: 1. for 循环没加{} 2. $\textbf{T_i}$, 想要加粗T,但是把i也扩进去了,latex就不懂了,于是一直recompile不出来说超时什么什么的,把i放到外面就 ...
- vue3.0+vite按需引入element plus
1.安装vite-plugin-style-import yarn add vite-plugin-style-import -D 2.在项目根目录下的vite.config.js中配置 import ...
- clamav测试用例 API
最近接触到clamav这一块,本身是一个很简单的任务,只需要调用他的API对文件进行检测即可,但是在进行大量搜索发现,网上最多只有API的讲解,且质量层次不齐,这可为难住我了,作为一个名副其实的&qu ...
- Shell写脚本关于ssh执行jar包,需要刷新JDK路径的问题
比如脚本中下面这一段 ssh $i "java -jar /applog/$PROJECT/$APPNAME --server.port=$SERVER_PORT >/dev/null ...
- Spring Boot中使用thymeleaf
Spring Boot支持FreeMarker.Groovy.Thymeleaf和Mustache四种模板解析引擎,官方推荐使用Thymeleaf. spring-boot-starter-thyme ...
- linux 串口查看信息
查看串口是否可用,可以对串口发送数据比如对com1口,echo helloworld >/dev/ttyS0 [root@H3LINUX90 ~]# echo helloworld >/d ...