设计模式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();
    }
}
相关推荐
罗曼蒂克在消亡2 分钟前
2.3MyBatis——插件机制
java·mybatis·源码学习
_GR14 分钟前
每日OJ题_牛客_牛牛冲钻五_模拟_C++_Java
java·数据结构·c++·算法·动态规划
无限大.27 分钟前
c语言200例 067
java·c语言·开发语言
余炜yw29 分钟前
【Java序列化器】Java 中常用序列化器的探索与实践
java·开发语言
攸攸太上29 分钟前
JMeter学习
java·后端·学习·jmeter·微服务
Kenny.志32 分钟前
2、Spring Boot 3.x 集成 Feign
java·spring boot·后端
不修×蝙蝠34 分钟前
八大排序--01冒泡排序
java
sky丶Mamba1 小时前
Spring Boot中获取application.yml中属性的几种方式
java·spring boot·后端
数据龙傲天1 小时前
1688商品API接口:电商数据自动化的新引擎
java·大数据·sql·mysql
刷帅耍帅2 小时前
设计模式-桥接模式
设计模式·桥接模式