设计模式3-行为模式-责任链模式

文章目录

责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。

当一个大的流程有很多步骤时,可以将些步骤链接起来 形成一个责任链,如果符合条件那么调用下一个链,如果不符合条件 那么跳过所有链。

一、责任链如何设计

1、定义责任链处理对象

每个链需要处理的逻辑,有一个统一的方法,这样便于统一调用,可以继承一个公共的抽象类

1.1、抽象类

java 复制代码
public abstract  class AbstractHandler {

    /**
     * 下一关用当前抽象类来接收
     */
    protected AbstractHandler next;

    public void setNext(AbstractHandler next) {
        this.next = next;
    }

    public abstract int handler();
}

1.2、责任链处理对象

java 复制代码
public class FirstPassHandler extends AbstractHandler {

    private int play(){
        return 80;
    }

    @Override
    public int handler(){
        System.out.println("第一关-->FirstPassHandler");
        int score = play();
        if(score >= 80){
            //分数>=80 并且存在下一关才进入下一关
            if(this.next != null){
                return this.next.handler();
            }
        }
        return score;
    }
}
java 复制代码
public class SecondPassHandler extends AbstractHandler  {


    private int play(){
        return 90;
    }

    public int handler(){
        System.out.println("第二关-->SecondPassHandler");

        int score = play();
        if(score >= 90){
            //分数>=90 并且存在下一关才进入下一关
            if(this.next != null){
                return this.next.handler();
            }
        }

        return score;
    }
}

2、将"每个链"组合起来,定一个枚举

2.1、枚举对象

java 复制代码
public enum  GatewayEnum {
    // handlerId, 拦截者名称,全限定类名,preHandlerId,nextHandlerId
    FIRST_HANDLER(new GatewayEntity(1, "api接口限流", "gateway.handler.FirstPassHandler", null, 2)),
    SECOND_HANDLER(new GatewayEntity(2, "黑名单拦截", "gateway.handler.SecondPassHandler", 1, null)),
    /*如果要 新增第三个责任链,则 再定一个枚举值,将 上一个枚举的 nextId 定义成 第新增的Id*/
    /*SESSION_HANDLER(new GatewayEntity(3, "用户会话拦截", "cn.dgut.design.chain_of_responsibility.GateWay.impl.SessionGatewayHandler", 2, null)),*/
    ;

    GatewayEntity gatewayEntity;

    public GatewayEntity getGatewayEntity() {
        return gatewayEntity;
    }

    GatewayEnum(GatewayEntity gatewayEntity) {
        this.gatewayEntity = gatewayEntity;
    }
}

2.2、责任链对象

java 复制代码
@Setter
@Getter
public class GatewayEntity {

    private String name;

    private String conference;

    private Integer handlerId;

    private Integer preHandlerId;

    private Integer nextHandlerId;

    public GatewayEntity(Integer handlerId,String name,String conference,Integer preId,Integer nextId){

        this.handlerId = handlerId;
        this.name = name;
        this.conference = conference;
        this.preHandlerId = preId;
        this.nextHandlerId = nextId;

    }
}

3、调用时,如何获取责任链对象

如果要调用这个责任链,那么肯定要将这些独立的"链" 链接起来,并获取第一个责任链对象,然后就可以调用了

3.1、获取责任链对象方法

java 复制代码
public interface GatewayDao {

    /**
     * 根据 handlerId 获取配置项
     * @param handlerId
     * @return
     */
    GatewayEntity getGatewayEntity(Integer handlerId);

    /**
     * 获取第一个处理者
     * @return
     */
    GatewayEntity getFirstGatewayEntity();
}
java 复制代码
public class GatewayImpl implements GatewayDao {

    /**
     * 初始化,将枚举中配置的handler初始化到map中,方便获取
     */
    private static Map<Integer, GatewayEntity> gatewayEntityMap = new HashMap<>();

    static {
        GatewayEnum[] values = GatewayEnum.values();
        for (GatewayEnum value : values) {
            GatewayEntity gatewayEntity = value.getGatewayEntity();
            gatewayEntityMap.put(gatewayEntity.getHandlerId(), gatewayEntity);
        }
    }


    @Override
    public GatewayEntity getGatewayEntity(Integer handlerId) {
        return gatewayEntityMap.get(handlerId);
    }

    @Override
    public GatewayEntity getFirstGatewayEntity() {
        for (Map.Entry<Integer, GatewayEntity> entry : gatewayEntityMap.entrySet()) {
            GatewayEntity value = entry.getValue();
            //  没有上一个handler的就是第一个
            if (value.getPreHandlerId() == null) {
                return value;
            }
        }
        return null;    
    }
}

3.2、责任链工厂方法--将这些独立的"链"链接起来,构成责任链,并返回第一个责任链接

java 复制代码
public class GatewayHandlerEnumFactory {

    private static GatewayDao gatewayDao = new GatewayImpl();
    // 提供静态方法,获取第一个handler

    /**
     * 设置 责任链 并返回第第一天 责任链
     * @return
     */
    public static AbstractHandler getFirstGatewayHandler() {

        GatewayEntity firstGatewayEntity = gatewayDao.getFirstGatewayEntity();
        AbstractHandler firstGatewayHandler = newGatewayHandler(firstGatewayEntity);
        if (firstGatewayHandler == null) {
            return null;
        }

        GatewayEntity tempGatewayEntity = firstGatewayEntity;
        Integer nextHandlerId = null;
        AbstractHandler tempGatewayHandler = firstGatewayHandler;
        // 迭代遍历所有handler,以及将它们链接起来
        while ((nextHandlerId = tempGatewayEntity.getNextHandlerId()) != null) {
            GatewayEntity gatewayEntity = gatewayDao.getGatewayEntity(nextHandlerId);
            AbstractHandler gatewayHandler = newGatewayHandler(gatewayEntity);
            tempGatewayHandler.setNext(gatewayHandler);
            tempGatewayHandler = gatewayHandler;
            tempGatewayEntity = gatewayEntity;
        }
        // 返回第一个handler
        return firstGatewayHandler;
    }

    /**
     * 反射实体化具体的处理者
     * @param firstGatewayEntity
     * @return
     */
    private static AbstractHandler newGatewayHandler(GatewayEntity firstGatewayEntity) {
        // 获取全限定类名
        String className = firstGatewayEntity.getConference();
        try {
            // 根据全限定类名,加载并初始化该类,即会初始化该类的静态段
            Class<?> clazz = Class.forName(className);
            return (AbstractHandler) clazz.newInstance();
        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }
}

4、调用

java 复制代码
public class GetewayClient {

    public static void main(String[] args) {
        AbstractHandler firstGetewayHandler = GatewayHandlerEnumFactory.getFirstGatewayHandler();
        firstGetewayHandler.handler();
    }
}
相关推荐
鹿角片ljp7 小时前
LeetCode 64:最小路径和复盘|二维 DP 与 ACM 模式完整写法
java·数据结构·算法
泡海椒8 小时前
PDF 表格样式优化:jquick-pdf 边框、圆角、背景色
java·开发语言·pdf
景熙552310 小时前
15.Java 8 Stream 流入门到实战
java·开发语言·数据结构
wno70410 小时前
Spring Security权限控制
java·python·spring
杨运交11 小时前
[071][验证码模块]基于Spring拦截器的验证码认证设计思想
java·后端·spring
Geek-Chow11 小时前
CountDownLatch in Java
java
SL_staff11 小时前
从RBAC到场景化授权:《无忧·企业文档》三级权限模型的技术实践解析
java·开源·产品
传奇开心果编程12 小时前
【springboot基础语法学与练】第 1 课:从零开始
java·spring boot·后端·学习
SL_staff12 小时前
财务系统慎用低代码?从数据模型闭环看合规落地的技术实践
java·低代码·全栈