设计模式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();
    }
}
相关推荐
NE_STOP1 小时前
MyBatis-plus进阶之映射与条件构造器
java
Seven974 小时前
NIO的零拷贝如何实现高效数据传输?
java
架构师沉默18 小时前
别又牛逼了!AI 写 Java 代码真的行吗?
java·后端·架构
后端AI实验室1 天前
我把一个生产Bug的排查过程,交给AI处理——20分钟后我关掉了它
java·ai
凉年技术1 天前
Java 实现企业微信扫码登录
java·企业微信
狂奔小菜鸡1 天前
Day41 | Java中的锁分类
java·后端·java ee
hooknum1 天前
学习记录:基于JWT简单实现登录认证功能-demo
java
程序员Terry1 天前
同事被深拷贝坑了3小时,我教他原型模式的正确打开方式
java·设计模式
NE_STOP1 天前
MyBatis-缓存与注解式开发
java
码路飞1 天前
不装 OpenClaw,我用 30 行 Python 搞了个 QQ AI 机器人
java