本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2024-11(1)

设计模式-责任链模式

发布于2020-11-19 20:21     阅读(691)     评论(0)     点赞(15)     收藏(4)


责任链模式

作用:

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

原理:

在这里插入图片描述

在这里插入图片描述


UML:

在这里插入图片描述


实际场景:

​ 1、当必须按顺序执行多个处理者时,可以使用该模式

​ 2、SpringMVC拦截器的使用

​ 3、网关拦截器使用


demo代码:

public class HandlerChain {

    // 持有所有Handler:
    private List<Handler> handlers = new ArrayList<>();

    public Handler init(){
        OneTaskHandler oneTaskHandler = new OneTaskHandler();
        TwoTaskHandler twoTaskHandler = new TwoTaskHandler();
        ThreeTaskHandler threeTaskHandler = new ThreeTaskHandler();
        oneTaskHandler.setNextHandler(twoTaskHandler);
        twoTaskHandler.setNextHandler(threeTaskHandler);
        return  oneTaskHandler;
    }
}
public abstract class Handler {

    /**下一步执行的任务*/
    private Handler nextHandler;

    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    /**任务处理*/
    public final void taskProcessing(Task task){
            this.taskReport(task);

            if(Objects.nonNull(this.nextHandler)){
                nextHandler.taskProcessing(task);
            }
    }

    /**从任务中获取能处理的任务级别*/
    protected abstract int getTaskLevel();

    /**输出任务*/
    protected abstract void taskReport(Task task);

}
public class OneTaskHandler extends Handler {

    @Override
    protected int getTaskLevel() {
        return 1;
    }

    @Override
    protected void taskReport(Task task) {
        System.out.println("一级任务进行处理");
    }
}
public class TwoTaskHandler extends Handler {

    @Override
    protected int getTaskLevel() {
        return 2;
    }

    @Override
    protected void taskReport(Task task) {
        System.out.println("二级任务进行处理");
    }
}
public class ThreeTaskHandler extends Handler {

    @Override
    protected int getTaskLevel() {
        return 3;
    }

    @Override
    protected void taskReport(Task task) {
        System.out.println("三级任务进行处理");
    }
}
public class Client {

    public static void main(String[] args) {

        HandlerChain handlerChain = new HandlerChain();
        Handler init = handlerChain.init();
        init.taskProcessing(new Task());

    }
}

实际场景代码:

  1)、静态设置:

    抽象内:

public abstract class GetewayHandlerAbstract {

    protected GetewayHandlerAbstract next;

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

    public final void taskProcess(Object RequestParams) {
        if(!this.servicDealWith(RequestParams)){
            //TODO 此处可以自行处理
            return;
        }

        if(this.next != null){
            this.next.taskProcess(RequestParams);
        }
    }

    /**service进行处理*/
    public abstract boolean servicDealWith(Object RequestParams);
}

   处理程序:

/**
 * api接口限流
 */
public class ApiLimitGetewayHandler extends GetewayHandlerAbstract{
    @Override
    public boolean servicDealWith(Object RequestParams) {
        //使用限流框架、获取使用信号量进行限流
        System.out.println("第一步,api接口限流校验");
        return true;
    }
}
/**
 * 黑名单拦截
 */
public class BlacklistGetwayHandler extends GetewayHandlerAbstract{
    public boolean servicDealWith(Object RequestParams) {
        //从数据库或者缓存中获取数据进行校验
        System.out.println("第二步,黑名单拦截校验");
        return true;
    }
}
/**
 * 参数过滤拦截
 */
public class ParamGetwayHandler extends GetewayHandlerAbstract{
    public boolean servicDealWith(Object requestParams) {
        //从请求的参数中获取参数,进行特殊字符或者敏感词汇进行过滤
        System.out.println("第四步,参数过滤拦截");
        return true;
    }
}
/**
 * 用户会话拦截
 */
public class SessionGetwayHandler extends GetewayHandlerAbstract {
    public boolean servicDealWith(Object RequestParams) {
        //从参数中获取用户的会话是不是又权限操作接口
        System.out.println("第三步,用户会话拦截校验");
        return true;
    }
}

    工厂方法:

public class GetewayHandlerFactory {

    public static GetewayHandlerAbstract GetewayHandler(){

        //TODO 像在程序种通过设置order 可以自行拿到Handler之后在进行一次排序

        //第一种通过手动自动设置
        //api接口限流
        GetewayHandlerAbstract apiLimitGetewayHandler = new ApiLimitGetewayHandler();
        //黑名单拦截
        GetewayHandlerAbstract blacklistGetwayHandler = new BlacklistGetwayHandler();
        //用户会话拦截
        GetewayHandlerAbstract sessionGetwayHandler = new SessionGetwayHandler();
        //参数过滤
        GetewayHandlerAbstract paramGetwayHandler = new ParamGetwayHandler();

        apiLimitGetewayHandler.setNext(blacklistGetwayHandler);//api接口限流的下一步是黑名单拦截
        blacklistGetwayHandler.setNext(sessionGetwayHandler);//黑白拦截的下一步是用户会话拦截
        sessionGetwayHandler.setNext(paramGetwayHandler);//用户会话拦截的下一步是参数果过滤拦截
        return apiLimitGetewayHandler;
    }
}

  2)、 动态设置:

    抽象类

public abstract class GetewayHandlerAbstract {

    protected GetewayHandlerAbstract next;

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

    public final void taskProcess(Object RequestParams) {
        if(!this.servicDealWith(RequestParams)){
            //TODO 此处可以自行处理
            return;
        }

        if(this.next != null){
            this.next.taskProcess(RequestParams);
        }
    }

    /**service进行处理*/
    public abstract boolean servicDealWith(Object RequestParams);
}

   处理程序:

/**
 * api接口限流
 */
public class ApiLimitGetewayHandler extends GetewayHandlerAbstract{
    @Override
    public boolean servicDealWith(Object RequestParams) {
        //使用限流框架、获取使用信号量进行限流
        System.out.println("第一步,api接口限流校验");
        return true;
    }
}
/**
 * 黑名单拦截
 */
public class BlacklistGetwayHandler extends GetewayHandlerAbstract{
    public boolean servicDealWith(Object RequestParams) {
        //从数据库或者缓存中获取数据进行校验
        System.out.println("第二步,黑名单拦截校验");
        return true;
    }
}
/**
 * 参数过滤拦截
 */
public class ParamGetwayHandler extends GetewayHandlerAbstract{
    public boolean servicDealWith(Object requestParams) {
        //从请求的参数中获取参数,进行特殊字符或者敏感词汇进行过滤
        System.out.println("第四步,参数过滤拦截");
        return true;
    }
}
/**
 * 用户会话拦截
 */
public class SessionGetwayHandler extends GetewayHandlerAbstract {
    public boolean servicDealWith(Object RequestParams) {
        //从参数中获取用户的会话是不是又权限操作接口
        System.out.println("第三步,用户会话拦截校验");
        return true;
    }
}

   dao:

public interface GetewayDao {

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

    /**
     * 获取第一个处理者
     * @return
     */
    GetewayEntity getFirstGetewayEntity();
}
public class GetewayDaoImpl implements GetewayDao{

    /**
     * 初始化,将枚举中配置的handler 初始化到map中,方便获取
     */
    private static Map<Integer, GetewayEntity> getewayEntityHashMap = new HashMap<Integer, GetewayEntity>();
    static {
        GetewayEnum[] values = GetewayEnum.values();
        for (GetewayEnum value : values) {
            GetewayEntity getewayEntity = value.getGetewayEntity();
            getewayEntityHashMap.put(getewayEntity.getHandlerId(),getewayEntity);
        }
    }

    @Override
    public GetewayEntity getGetewayEntity(Integer handlerId) {
        return getewayEntityHashMap.get(handlerId);
    }

    /**
     * 获取第一个handler的配置项 枚举
     * @return
     */
    @Override
    public GetewayEntity getFirstGetewayEntity(){
        for(Map.Entry<Integer,GetewayEntity> entry : getewayEntityHashMap.entrySet()){
            GetewayEntity value = entry.getValue();
            //  没有上一个handler的就是第一个
            if(value.getParnerHandlerId() == null){
                return value;
            }
        }
        return  null;
    }

}

   实体对象

@Data
public class GetewayEntity {

    private Integer handlerId;
    private String msg;
    private String handlerClassName;
    private Integer parnerHandlerId;
    private Integer nextHandlerId;
}

   数据层:(这里也可以是数据库的表)

/***

CREATE TABLE `handler_task` (
	`id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '自增id',
	`handler_id` INT(11) NULL DEFAULT '0' COMMENT '当前handler的Id',
	`msg` INT(11) NULL DEFAULT NULL COMMENT '描述',
	`handler_class_name` VARCHAR(50) NULL DEFAULT NULL COMMENT '对用springService的名称或者全类名' COLLATE 'utf8_general_ci',
	`parner_handler_id` VARCHAR(50) NULL DEFAULT NULL COMMENT '父级handler的Id' COLLATE 'utf8_general_ci',
	`next_nandler_id` VARCHAR(50) NULL DEFAULT NULL COMMENT '下一级别的handler的Id' COLLATE 'utf8_general_ci',
	`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
	`create_by` VARCHAR(50) NULL DEFAULT NULL COMMENT '创建者' COLLATE 'utf8_general_ci',
	`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
	`update_by` VARCHAR(50) NULL DEFAULT NULL COMMENT '修改者' COLLATE 'utf8_general_ci'
	PRIMARY KEY (`id`) USING BTREE
)
COMMENT='处理任务过程表'
COLLATE='utf8_general_ci'
ENGINE=InnoDB=
;

**/



public enum GetewayEnum {
    /**
     * 在这里大家需要注意到一个点 api接口限流是第一个处理者 因此没有 prehandlerId,也就是 它的prehandlerId = null
     */
    API_HANDLER(new GetewayEntity(1,"api接口限流","chain_of_responsibility.cases.statics.handler.ApiLimitGetewayHandler",null,2)),
    BLACKLIST_HANDLER(new GetewayEntity(2,"黑名单拦截","chain_of_responsibility.cases.statics.handler.BlacklistGetwayHandler",1,3)),
    SESSION_HANDLER(new GetewayEntity(3,"用户会话拦截","chain_of_responsibility.cases.statics.handler.SessionGetwayHandler",2,4)),

    /**
     * 这是最后一个处理者,因此没有下一个 nexthandlerId 也就是它的 nexthandlerId = null
     */
    PARAM_HANDLER(new GetewayEntity(4,"参数过滤拦截","chain_of_responsibility.cases.statics.handler.ParamGetwayHandler",3,null)),
    ;

    GetewayEntity getewayEntity;

    public GetewayEntity getGetewayEntity() {
        return getewayEntity;
    }

    GetewayEnum(GetewayEntity getewayEntity) {
        this.getewayEntity = getewayEntity;
    }
}

   工厂方法:

ublic class GetewayHandlerEnumFactory {

    private static GetewayDao getewayDao = new GetewayDaoImpl();

    public static GetewayHandlerAbstract getFirstGetewayHandler1(){
        // 1\. 获取第一处理者 那么那个是第一个处理者呢 prehandlerId == null 的就是第一个handler
        GetewayEntity firstGetewayEntity = getewayDao.getFirstGetewayEntity();
        GetewayHandlerAbstract firstGetewayHandler = newGetewayHandler(firstGetewayEntity);

        if(firstGetewayHandler == null){
            return null;
        }
        setNextGetewayHandler(firstGetewayEntity,firstGetewayHandler);

        return firstGetewayHandler;
    }

    private static void setNextGetewayHandler(GetewayEntity getewayEntity,GetewayHandlerAbstract getewayHandler){
        if(getewayHandler != null && getewayEntity != null){
            Integer nexthandlerId = getewayEntity.getNextHandlerId();
            GetewayEntity nextGetewayEntity = getewayDao.getGetewayEntity(nexthandlerId);
            GetewayHandlerAbstract nextGetewayHandler = newGetewayHandler(nextGetewayEntity);
            getewayHandler.setNext(nextGetewayHandler);
            //递归 设置
            setNextGetewayHandler(nextGetewayEntity,nextGetewayHandler);
        }
    }

    /**
     * 反射实体化具体的处理者
     * @param getewayEntity
     * @return
     */
    private static GetewayHandlerAbstract newGetewayHandler(GetewayEntity getewayEntity){
        if(getewayEntity == null){
            return null;
        }
        String handlerClassName = getewayEntity.getHandlerClassName();
        try {
            Class<?> clazz = Class.forName(handlerClassName);
            return (GetewayHandlerAbstract) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}

   测试:此处的测试在实际项目中是存放在拦截器或者过滤器中等

public class GetewayClient {
    public static void main(String[] args) {
        GetewayHandlerAbstract firstGetewayHandler = GetewayHandlerEnumFactory.getFirstGetewayHandler1();
        Object params = new Object();
        firstGetewayHandler.taskProcess(params);
    }
}

这只是针对于接口层做了链式处理,责任链真正的思想是链式处理,别被这一个场景给误导,具体真实场景还可以是(WETSV) 算每一个层级,下一个层级依赖上一个层级的数据,WE->WET->WETS->WETSV


优点:

  • 你可以控制请求处理的顺序。
  • 单一职责原则。 你可对发起操作和执行操作的类进行解耦。
  • 开闭原则。 你可以在不更改现有代码的情况下在程序中新增处理者。

与其他模式的关系

  • 责任链模式命令模式中介者模式观察者模式用于处理请求发送者和接收者之间的不同连接方式:

    • 责任链按照顺序将请求动态传递给一系列的潜在接收者, 直至其中一名接收者对请求进行处理。
    • 命令在发送者和请求者之间建立单向连接。
    • 中介者清除了发送者和请求者之间的直接连接, 强制它们通过一个中介对象进行间接沟通。
    • 观察者允许接收者动态地订阅或取消接收请求。
  • 责任链通常和组合模式结合使用。 在这种情况下, 叶组件接收到请求后, 可以将请求沿包含全体父组件的链一直传递至对象树的底部。

  • 责任链的管理者可使用命令模式实现。 在这种情况下, 你可以对由请求代表的同一个上下文对象执行许多不同的操作。

    还有另外一种实现方式, 那就是请求自身就是一个命令对象。 在这种情况下, 你可以对由一系列不同上下文连接而成的链执行相同的操作。

  • 责任链装饰模式的类结构非常相似。 两者都依赖递归组合将需要执行的操作传递给一系列对象。 但是, 两者有几点重要的不同之处。

    责任链的管理者可以相互独立地执行一切操作, 还可以随时停止传递请求。 另一方面, 各种装饰可以在遵循基本接口的情况下扩展对象的行为。 此外, 装饰无法中断请求的传递。


参考

https://zhuanlan.zhihu.com/p/99334096.


结束

 整理不易,记得点个赞,你的支持是我最大的动力


❤️❤️写优质博客 培养优秀思想 ❤️❤️

原文链接:https://blog.csdn.net/qq_25582465/article/details/109766576



所属网站分类: 技术文章 > 博客

作者:你不要惹我

链接:http://www.javaheidong.com/blog/article/823/b974bf2b46ea57b503d0/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

15 0
收藏该文
已收藏

评论内容:(最多支持255个字符)