设计模式——责任链

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

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

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

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

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

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

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

使用场景:

  • 多条件流程判断:权限控制
  • 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;

    // 可以根据实际需求增加字段,用于给不同处理类进行判断是否有权限处理,这里一律假设为字段condition
    private 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);
        }
    }

    @Override
    public GatewayEntity getFirstGatewayEntity() {
        for (Map.Entry<Integer, GatewayEntity> entry : map.entrySet()) {
            GatewayEntity value = entry.getValue();
            if(value.getPreHandlerId() == null){
                return value;
            }
        }
        return null;
    }

    @Override
    public 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 {

    @Override
    public 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 {

    @Override
    public 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 {

    @Override
    public 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();

    // 提供静态方法,获取第一个handler
    public 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;
        }
        // 返回第一个handler
        return 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数字时代的软件架构:持续架构的兴起与架构师角色的转变

在数字化浪潮的推动下&#xff0c;软件架构领域正经历着前所未有的变革。Eoin Woods在《数字时代的软件架构》演讲中&#xff0c;深入探讨了这一变革&#xff0c;并提出了“持续架构”这一概念。本文将基于Eoin的观点&#xff0c;结合个人理解&#xff0c;探讨持续架构的重要性…

2000-2021年县域金融机构存贷款数据

2000-2021年县域金融机构存贷款数据 1、时间&#xff1a;2000-2021年 2、指标&#xff1a;统计年度、地区编码ID、县域代码、县域名称、所属地级市、所属省份、年末金融机构贷款余额/亿元、年末金融机构存款余额/亿元、年末城乡居民储蓄存款余额/亿元 3、来源&#xff1a;县…

音频Balance源码总结

音频Balance源码总结 何为音频Balance&#xff1f; 顾名思义&#xff0c;Balance及平衡&#xff0c;平衡也就是涉及多方&#xff0c;音频左右甚至四通道&#xff0c;调节所有通道的音量比&#xff0c;使用户在空间内听到各个通道的音频大小不一&#xff0c;好似置身于真实环境…

姚期智、张亚勤、薛澜、Stuart Russell、Max Tegmark,DeepMind研究员等共话全球AI治理丨大会回顾...

为什么AI安全已迫在眉睫&#xff1f;如何构建全球范围内的合作&#xff1f;民众该如何参与到其中&#xff1f;未来的AI系统将是什么样的&#xff1f; 2024年6月15日&#xff0c;智源大会第二天&#xff0c;多位AI安全领域专家进行圆桌讨论&#xff0c;连接中国北京和美国加利福…

Android隐藏状态栏和修改状态栏颜色_亲测有效

本文记录了隐藏状态栏和修改状态栏颜色以及电量、WiFi标志等内容的模式显示&#xff0c;亲测有效。 1、隐藏屏幕状态栏 public void hideStatusBar(BaseActivity activity) {Window window activity.getWindow();//没有这一行无效window.addFlags(WindowManager.LayoutParam…

基于自组织长短期记忆神经网络的时间序列预测(MATLAB)

LSTM是为了解决RNN 的梯度消失问题而诞生的特殊循环神经网络。该网络开发了一种异于普通神经元的节点结构&#xff0c;引入了3 个控制门的概念。该节点称为LSTM 单元。LSTM 神经网络避免了梯度消失的情况&#xff0c;能够记忆更长久的历史信息&#xff0c;更能有效地拟合长期时…

Spring Cloud LoadBalancer基础入门与应用实践

官网地址&#xff1a;https://docs.spring.io/spring-cloud-commons/reference/spring-cloud-commons/loadbalancer.html 【1】概述 Spring Cloud LoadBalancer是由SpringCloud官方提供的一个开源的、简单易用的客户端负载均衡器&#xff0c;它包含在SpringCloud-commons中用…

[OtterCTF 2018]Recovery

里克必须找回他的文件&#xff01;用于加密文件的随机密码是什么 恢复他的文件 &#xff0c;感染的文件 &#xff1f; vmware-tray.ex 前面导出的3720.dmp 查找一下 搜索主机 strings -e l 3720.dmp | grep “WIN-LO6FAF3DTFE” 主机名 后面跟着一串 代码 aDOBofVYUNVnmp7 是不…

C++并发之环形队列(ring,queue)

目录 1 概述2 实现3 测试4 运行 1 概述 最近研究了C11的并发编程的线程/互斥/锁/条件变量&#xff0c;利用互斥/锁/条件变量实现一个支持多线程并发的环形队列&#xff0c;队列大小通过模板参数传递。 环形队列是一个模板类&#xff0c;有两个模块参数&#xff0c;参数1是元素…

【操作系统期末速成】 EP02 | 学习笔记(基于五道口一只鸭)

文章目录 一、前言&#x1f680;&#x1f680;&#x1f680;二、正文&#xff1a;☀️☀️☀️2.1 考点二&#xff1a;操作系统的功能及接口2.2 考点三&#xff1a;操作系统的发展及分类2.3 考点四&#xff1a;操作系统的运行环境&#xff08;重要&#xff09; 一、前言&#x…

C++输出彩色方块

1.使用方法 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 0xab); ———————————————————————————————————————— 0 黑色 1 蓝色 2 绿色 3 湖蓝色 4 红色 5 紫色 6 黄色 7 白色 8 灰色 9 …

【限免】线性调频信号的脉冲压缩及二维分离SAR成像算法【附MATLAB代码】

文章来源&#xff1a;微信公众号&#xff1a;EW Frontier QQ交流群&#xff1a;949444104 程序一 对线性调频信号进行仿真&#xff0c;输出其时频域的相关信息&#xff0c;并模拟回波信号&#xff0c; 对其进行脉冲压缩和加窗处理。 实验记录&#xff1a; 1.线性调频信号时…

24年hvv前夕,微步也要收费了,情报共享会在今年结束么?

一个人走的很快&#xff0c;但一群人才能走的更远。吉祥同学学安全https://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247483727&idx1&sndb05d8c1115a4539716eddd9fde4e5c9&scene21#wechat_redirect这个星球&#x1f517;里面已经沉淀了&#xff1a; 《Ja…

自闭症早期风险判别和干预新路径

谷禾健康 自闭症谱系障碍 (ASD) 是一组神经发育疾病&#xff0c;其特征是社交互动和沟通的质量障碍、兴趣受限以及重复和刻板行为。 环境因素在自闭症中发挥重要作用&#xff0c;多项研究以及谷禾队列研究文章表明肠道微生物对于自闭症的发生和发展以及存在明显的菌群和代谢物的…

智慧校园-报修管理系统总体概述

智慧校园报修管理系统是专为优化教育机构内部维修报障流程而设计的信息化解决方案&#xff0c;它通过集成现代信息技术&#xff0c;为校园设施的维护管理带来革新。该系统以用户友好和高效运作为核心&#xff0c;确保了从报修请求提交到问题解决的每一个步骤都顺畅无阻。 师生或…

Apache IoTDB 监控详解 | 分布式系统监控基础

IoTDB 分布式系统监控的基础“须知”&#xff01; 我这个环境的系统性能一直无法提升&#xff0c;能否帮我找到系统的瓶颈在哪里&#xff1f; 系统优化后&#xff0c;虽然写入性能有所提升&#xff0c;但查询延迟却增加了&#xff0c;下一步我该如何排查和优化呢&#xff1f; 请…

【折腾笔记】兰空图床使用Minio作为储存策略

前言 花了几个小时研究了一下在兰空图床中使用Minio作为存储策略,官方并没有给出太多关于minio的储存策略配置文档,我是经过反复尝试,然后根据错误日志的提示以及查阅兰空图床在GitHub上面的issues悟出来的配置方法。 因为我的兰空图床和Minio都是基于群晖的NAS设备DS423+…

[OtterCTF 2018]Bit 4 Bit

我们已经发现这个恶意软件是一个勒索软件。查找攻击者的比特币地址。** 勒索软件总喜欢把勒索标志丢在显眼的地方&#xff0c;所以搜索桌面的记录 volatility.exe -f .\OtterCTF.vmem --profileWin7SP1x64 filescan | Select-String “Desktop” 0x000000007d660500 2 0 -W-r-…

Debian/Ubuntu Linux安装OBS

先决条件 建议使用 xserver-xorg 1.18.4 或更新版本&#xff0c;以避免 OBS 中某些功能&#xff08;例如全屏投影仪&#xff09;出现潜在的性能问题。在 Linux 上使用 OBS Studio 需要 OpenGL 3.3&#xff08;或更高版本&#xff09;支持。在终端中输入以下内容来检查系统支持…

几个常见的FPGA问题之序列发生器、编码器、D触发器

几个常见的FPGA问题之序列发生器、编码器、D触发器 语言 :Verilg HDL 、VHDL EDA工具: Vivado 几个常见的FPGA问题之序列发生器、编码器、D触发器一、引言二、背景1、序列发生器(Sequence Generator)2、编码器(Encoder)3、D触发器(D Flip-Flop)二、问题及解决方案1. 序…