设计模式——责任链

责任链模式是一种行为设计模式,用于将请求的发送者和接收者解耦。在这种模式中,请求通过一条由多个对象组成的链传递,直到有一个对象能够处理该请求为止。每个对象都可以决定是否处理请求以及是否将请求传递给下一个对象。

责任链模式通常在以下场景中使用:

处理请求的对象可能不确定:当请求的处理对象需要动态确定时,可以使用责任链模式。责任链模式允许请求在链中传递,直到有一个处理者能够处理该请求。

需要避免发送者和接收者之间的耦合:责任链模式可以将发送者和接收者解耦,发送者不需要知道具体的接收者是谁,只需要将请求发送给责任链的第一个处理者即可。

处理请求的对象集合需要动态组合:责任链模式允许动态地组织处理请求的对象集合,可以根据需要灵活地添加、删除或修改处理者,而不影响客户端的代码。

处理请求的对象需要按顺序执行:如果需要按照一定的顺序依次执行处理者来处理请求,责任链模式是一个很好的选择。

需要对请求的发送者和接收者进行解耦:责任链模式可以帮助发送者和接收者之间的解耦,发送者只需要将请求发送给责任链的第一个处理者,而不需要知道请求最终由谁来处理。

使用场景:

  • 多条件流程判断:权限控制
  • ERP系统流程审批:总经理、人事经理、项目经理
  • Java过滤器的底层实现Filter

假设现在有一个闯关游戏,进入下一关的条件是上一关的分数要高于 xx,并且每一关的实际内容都不一样,那么就需要创建每个关卡的对应类

//第一关
public class FirstPassHandler {public int handler(){System.out.println("第一关-->FirstPassHandler");return 80;}
}
//第二关
public class SecondPassHandler {public int handler(){System.out.println("第二关-->SecondPassHandler");return 90;}
}
//第三关
public class ThirdPassHandler {public int handler(){System.out.println("第三关-->ThirdPassHandler,这是最后一关啦");return 95;}
}//客户端
public class HandlerClient {public static void main(String[] args) {FirstPassHandler firstPassHandler = new FirstPassHandler();//第一关SecondPassHandler secondPassHandler = new SecondPassHandler();//第二关ThirdPassHandler thirdPassHandler = new ThirdPassHandler();//第三关int firstScore = firstPassHandler.handler();//第一关的分数大于等于80则进入第二关if(firstScore >= 80){int secondScore = secondPassHandler.handler();//第二关的分数大于等于90则进入第二关if(secondScore >= 90){thirdPassHandler.handler();}}}
}

注意,如果关卡特别多,那么主函数代码的if判断就开始变得复杂。

责任链工厂实现网关权限控制

在网关作为微服务程序的入口,拦截客户端所有的请求实现权限控制 ,比如先判断Api接口限流、黑名单、用户会话、参数过滤。 Api接口限流→黑名单拦截→用户会话→参数过滤

  • 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
  • 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  • 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

在这里插入图片描述

具体实现思路:通过配置文件或者枚举类的方式表明角色之间的关系,然后通过链表连接起来,形成责任链的方式,然后再每个权限控制处理类上抽象出一个父类或者接口,每个具体的处理类去继承或者实现。

在这里插入图片描述
定义实体类GatewayEntity,其中包括权限的名称和具体的处理类路径(用于反射寻找具体处理类):

@Data
@AllArgsConstructor
public class GatewayEntity {private Integer handlerId;private String name;private String conference;// 可以根据实际需求增加字段,用于给不同处理类进行判断是否有权限处理,这里一律假设为字段conditionprivate String condition;private Integer preHandlerId;private Integer nextHandlerId;}

定义枚举类GatewayEnum,排列好关系(也可也将这些关系通过数据库表的方式存储):

方式1:

public enum GatewayEnum {API_HANDLER(new GatewayEntity(1, "api 接口限流", "GateWay.Impl.ApiLimitGatewayHandler", "条件1", null, 2)),BLACKLIST_HANDLER(new GatewayEntity(2, "黑名单列表拦截", "GateWay.Impl.BlacklistGatewayHandler", "条件2", 1, 3)),SESSION_HANDLER(new GatewayEntity(3, "用户会话拦截", "GateWay.Impl.SessionGatewayHandler", "条件3", 2, null));GatewayEntity gatewayEntity;public GatewayEntity getGatewayEntity(){return gatewayEntity;}GatewayEnum(GatewayEntity gatewayEntity){this.gatewayEntity = gatewayEntity;}}

方式2:

CREATE TABLE `gateway_handler` (`handlerId` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`name` varchar(32) DEFAULT NULL COMMENT 'handler名称',`conference` varchar(32) DEFAULT NULL COMMENT 'handler主键id',`condition` varchar(32) DEFAULT NULL COMMENT '判断需求字段',`prev_handler_id` int(11) DEFAULT NULL,`next_handler_id` int(11) DEFAULT NULL COMMENT '下一个handler',PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COMMENT='权限表';-- ----------------------------
-- Records of gateway_handler
-- ----------------------------
INSERT INTO `gateway_handler` VALUES ('1', 'Api接口限流', 'GateWay.Impl.ApiLimitGatewayHandler', "条件1", null, '2');
INSERT INTO `gateway_handler` VALUES ('2', '黑名单列表拦截', 'GateWay.Impl.BlacklistGatewayHandler', "条件2", '1', '3');
INSERT INTO `gateway_handler` VALUES ('3', '用户会话拦截', 'GateWay.Impl.SessionGatewayHandler', "条件3", '2', null);

定义逻辑接口层GatewayDao,编写获取实体类GatewayEntity的接口:

public interface GatewayDao {GatewayEntity getFirstGatewayEntity();GatewayEntity getGatewayEntity(Integer handlerId);}

逻辑接口的具体实现GatewayImpl:

public class GatewayImpl implements GatewayDao{private static Map<Integer, GatewayEntity> map = new HashMap<Integer, GatewayEntity>();/*** 初始化,将枚举中配置的handler初始化到map中,方便获取*/static {GatewayEnum[] values = GatewayEnum.values();for (GatewayEnum value : values) {GatewayEntity gatewayEntity = value.getGatewayEntity();map.put(gatewayEntity.getHandlerId(), gatewayEntity);}}@Overridepublic GatewayEntity getFirstGatewayEntity() {for (Map.Entry<Integer, GatewayEntity> entry : map.entrySet()) {GatewayEntity value = entry.getValue();if(value.getPreHandlerId() == null){return value;}}return null;}@Overridepublic GatewayEntity getGatewayEntity(Integer handlerId) {return map.get(handlerId);}
}

将每个权限控制的具体实现抽象出来,编写GatewayHandler抽象类:

@Data
public abstract class GatewayHandler {// 下一关卡的处理类protected GatewayHandler next;public String condition;// 通过传入条件判断对象是否能够处理请求public abstract String service(String condition);public void setNext(GatewayHandler next){this.next = next;}
}

每个不同权限控制的具体实现类:

public class ApiLimitGatewayHandler extends GatewayHandler {@Overridepublic String service(String condition) {System.out.println("第一关->api接口限流");if(!this.condition.equals(condition)){System.out.println("我是第一关,但我的权限不够,我给下一个节点");if(this.next != null){return this.next.service(condition);}}System.out.println("我是第一关,我自己能处理");return condition;}
}public class BlacklistGatewayHandler extends GatewayHandler {@Overridepublic String service(String condition) {System.out.println("第二关->黑名单列表拦截");if(!this.condition.equals(condition)){System.out.println("我是第二关,但我的权限不够,我给下一个节点");if(this.next != null){return this.next.service(condition);}}System.out.println("我是第二关,我自己能处理");return condition;}
}public class SessionGatewayHandler extends GatewayHandler {@Overridepublic String service(String condition) {System.out.println("第三关->用户会话拦截");if(!this.condition.equals(condition)){System.out.println("我是第三关,但我的权限也不够,处理不了,而且我后面没人了");}else{System.out.println("我是第三关,我可以处理");}return condition;}}

通过工厂类GatewayHandlerEnumFactory 按顺序连接不同的处理类(权限控制的具体内容)

public class GatewayHandlerEnumFactory {private static GatewayDao gatewayDao = new GatewayImpl();// 提供静态方法,获取第一个handlerpublic static GatewayHandler getFirstGatewayHandler(){GatewayEntity firstGatewayEntity = gatewayDao.getFirstGatewayEntity();GatewayHandler firstGatewayHandler = newGatewayHandler(firstGatewayEntity);if(firstGatewayHandler == null){return null;}firstGatewayHandler.setCondition(firstGatewayEntity.getCondition());GatewayEntity tempGatewayEntity = firstGatewayEntity;GatewayHandler tempGatewayHandler = firstGatewayHandler;Integer nextHandlerId = null;// 迭代遍历所有handler,以及将它们链接起来while((nextHandlerId = tempGatewayEntity.getNextHandlerId()) != null){GatewayEntity gatewayEntity = gatewayDao.getGatewayEntity(nextHandlerId);GatewayHandler gatewayHandler = newGatewayHandler(gatewayEntity);gatewayHandler.setCondition(gatewayEntity.getCondition());tempGatewayHandler.setNext(gatewayHandler);tempGatewayHandler = gatewayHandler;tempGatewayEntity = gatewayEntity;}// 返回第一个handlerreturn firstGatewayHandler;}/*** 通过反射实例化具体的处理者* @param firstGatewayEntity* @return*/public static GatewayHandler newGatewayHandler(GatewayEntity firstGatewayEntity){String conference = firstGatewayEntity.getConference();try {Class<?> clazz = Class.forName(conference);return (GatewayHandler) clazz.newInstance();} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {e.printStackTrace();}return null;}}

编写主类,进行测试:

public class GatewayClient {public static void main(String[] args) {GatewayHandler gatewayHandler = GatewayHandlerEnumFactory.getFirstGatewayHandler();gatewayHandler.service("条件1");System.out.println();gatewayHandler.service("条件2");System.out.println();gatewayHandler.service("条件3");System.out.println();gatewayHandler.service("条件4");}
}---输出---
第一关->api接口限流
我是第一关,我自己能处理第一关->api接口限流
我是第一关,但我的权限不够,我给下一个节点
第二关->黑名单列表拦截
我是第二关,我自己能处理第一关->api接口限流
我是第一关,但我的权限不够,我给下一个节点
第二关->黑名单列表拦截
我是第二关,但我的权限不够,我给下一个节点
第三关->用户会话拦截
我是第三关,我可以处理第一关->api接口限流
我是第一关,但我的权限不够,我给下一个节点
第二关->黑名单列表拦截
我是第二关,但我的权限不够,我给下一个节点
第三关->用户会话拦截
我是第三关,但我的权限也不够,处理不了,而且我后面没人了Process finished with exit code 0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/34780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

螺丝扭断力试验机SJ-12

一、设备简介&#xff1a; 螺丝扭断力试验机用于测试螺丝的耐扭断力。本机将螺丝产品所受到轴向扭转力与反作用力&#xff0c;常用扭力扳手来计量。本机可对产品进行转力测、锁动测试、锁动扭力测试等多种测试方式。 二、设备使用&#xff1a; 1、将螺丝强度扭力试验机底座锁于…

代码随想录-Day41

46. 携带研究材料&#xff08;第六期模拟笔试&#xff09; 题目描述 小明是一位科学家&#xff0c;他需要参加一场重要的国际科学大会&#xff0c;以展示自己的最新研究成果。他需要带一些研究材料&#xff0c;但是他的行李箱空间有限。这些研究材料包括实验设备、文献资料和实…

Mysql数据库学习

1、数据库基本认知 一&#xff1a;数据库分类 关系型数据库&#xff1a;SQL 主要有MySQL,Oracle,Sql Server等&#xff0c;其主要通过表与表之间&#xff0c;行与列之间的关系进行数据的存储。可以通过外键来建立表之间的关联。 非关系型数据库&#xff1a;NoSQL 主要有HB…

分享一个 MySQL 简单快速进行自动备份和还原的脚本和方法

前言 数据备份和还原在信息技术领域中具有非常重要的作用&#xff0c;不论是人为误操作、硬件故障、病毒感染、自然灾害还是其他原因&#xff0c;数据丢失的风险都是存在的。如果没有备份&#xff0c;一旦数据丢失&#xff0c;可能对个人、企业甚至整个组织造成巨大的损失。 …

uniapp H5端使用百度地图

1、登录百度地图开放平台 https://lbsyun.baidu.com/&#xff08;没有账号则先去创建一个百度账号&#xff09; 2、进入百度地图开放平台控制台&#xff08;导航栏“控制台”&#xff09;&#xff0c;点击“应用管理”-“我的应用” 3、选择“创建应用”&#xff0c;应用模块选…

msvcr110.dll丢失的解决方法,亲测有效的几种解决方法

最近&#xff0c;我在启动一个程序时&#xff0c;系统突然弹出一个错误提示&#xff0c;告诉我电脑缺失了一个名为msvcr110.dll的文件。这让我感到非常困惑&#xff0c;因为我之前从未遇到过这样的问题。经过一番搜索和尝试&#xff0c;我总结了5种靠谱的解决方法。下面分享给大…

高效运维:标准化与智能化的运维流程管理实践

高效运维&#xff1a;标准化与智能化的运维流程管理实践 在信息化建设日益深化的今天&#xff0c;运维流程管理已成为企业确保其信息系统稳定、高效运行的关键手段。通过系统化、标准化的运维流程管理&#xff0c;企业能够有效预防系统故障&#xff0c;提升服务质量&#xff0…

React的路由(ReactRouter)-路由导航跳转

1.第一步 // createBrowserRouter路由 RouterProvider组件 import {createBrowserRouter,RouterProvider} from react-router-dom // 创建router实例对象&#xff0c;并配置路由对应关系 const routercreateBrowserRouter([{path:/login,element:<div>我是登录页</di…

vue3-登录小案例(借助ElementPlus+axios)

1.创建一个vue3的项目。 npm create vuelatest 2.引入Elementplus组件库 链接&#xff1a;安装 | Element Plus npm install element-plus --save 在main.js中引入 import ElementPlus from "element-plus";import "element-plus/dist/index.css";ap…

python--序列化模块json与pickle

什么叫序列化&#xff1f; 将原本的字典、列表等内容转换成一个字符串的过程就 叫做序列化。 多用的两个序列化模块&#xff1a;json与pickle json&#xff0c;用于字符串 和 python数据类型间进行转换 pickle&#xff0c;用于python特有的类型 和 python的数据类型间进行转换 …

Scania斯堪尼亚SHL题库综合能力性格测试真题题型解析及面试经验

一、走进Scania斯堪尼亚 Scania是一家成立于1891年的瑞典公司&#xff0c;专注于重型卡车和巴士的制造&#xff0c;以其模块化系统和环保设计闻名。作为全球领先的运输解决方案提供商&#xff0c;Scania不仅提供高质量的车辆&#xff0c;还提供相关服务和融资解决方案。公司秉…

Ruby langchainrb gem and custom configuration for the model setup

题意&#xff1a;Ruby 的 langchainrb gem 以及针对模型设置的自定义配置 问题背景&#xff1a; I am working in a prototype using the gem langchainrb. I am using the module assistant module to implemente a basic RAG architecture. 我正在使用 langchainrb 这个 ge…

实战|记一次java协同办公OA系统源码审计

前言 因为笔者也是代码审计初学者&#xff0c;写得不好的地方请见谅。该文章是以项目实战角度出发&#xff0c;希望能给大家带来启发。 审计过程 审计思路 1、拿到一个项目首先要看它使用了什么技术框架&#xff0c;是使用了ssh框架&#xff0c;还是使用了ssm框架&#xff…

C#基于SkiaSharp实现印章管理(2)

上一篇文章最后提到基于System.Text.Json能够序列化SKColor对象&#xff0c;但是反序列化时却无法解析本地json数据。换成Newtonsoft.Json进行序列化和反序列化也是类似的问题。   通过百度及查看微软的帮助文档&#xff0c;上述情况下需自定义转换类以处理SKColor类型数据的…

搜维尔科技:【研究】触觉手套比控制器更能带来身临其境、更安全、更高效的虚拟体验

自然交互可提高VR模拟的有效性。研究表明&#xff0c;触觉手套比控制器更能带来身临其境、更安全、更高效的虚拟体验。 以下是验证 医疗培训中的触觉技术 “ 95.5%的参与者表示触摸是 XR 教育的重要组成部分&#xff0c;90.9% 的参与者表示 XR 触觉将提供一个安全的学习场所。…

经典文献阅读之--MobileViT(轻量级、通用且移动友好的网络框架)

Tip: 如果你在进行深度学习、自动驾驶、模型推理、微调或AI绘画出图等任务&#xff0c;并且需要GPU资源&#xff0c;可以考虑使用UCloud云计算旗下的Compshare的GPU算力云平台。他们提供高性价比的4090 GPU&#xff0c;按时收费每卡2.6元&#xff0c;月卡只需要1.7元每小时&…

尚品汇-(七)

&#xff08;1&#xff09;在网关中实现跨域 全局配置类实现 包名&#xff1a;com.atguigu.gmall.gateway.config 创建CorsConfig类 Configuration public class CorsConfig {Beanpublic CorsWebFilter corsWebFilter(){// cors跨域配置对象CorsConfiguration configuration…

私有化部署ChatGPT:潜力与挑战

背景 以ChatGPT为代表的大语言模型服务在2023年初开始大规模爆发&#xff0c;AI技术从来没有如此接近普通民众。随着以Microsoft&#xff0c; Google&#xff0c; Meta &#xff08;Facebook&#xff09;为代表的科技巨头在AI技术领域相继发布重量级产品和服务&#xff0c;国内…

声场合成新方法:基于声波传播的框架

声场合成是指在房间内的麦克风阵列上&#xff0c;根据来自房间内其他位置的声源信号&#xff0c;合成每个麦克风的音频信号。它是评估语音/音频通信设备性能指标的关键任务&#xff0c;因为它是一种成本效益高的方法&#xff0c;用于数据生成以替代真实的数据收集&#xff0c;后…

武汉星起航:挂牌上海股权交易中心,自营店铺销售额迎飞跃式增长

2023年10月30日&#xff0c;对于武汉星起航电子商务有限公司而言&#xff0c;无疑是一个载入史册的重要日子。这一天&#xff0c;公司成功在上海股权托管交易中心挂牌展示&#xff0c;正式登陆资本市场&#xff0c;开启了全新的发展篇章。这一里程碑式的跨越&#xff0c;不仅彰…