设计模式之【责任链模式】,路铺好了,你走不走?

news2025/1/9 3:59:10

文章目录

  • 一、什么是责任链模式
    • 1、状态模式与责任链模式的区别
    • 2、责任链模式使用场景
    • 3、责任链模式的优缺点
    • 4、责任链模式的角色
  • 二、实例
    • 1、责任链模式的一般写法
      • (1)一般写法
      • (2)一般写法-使用建造者模式进阶
      • (3)进阶写法①
      • (4)进阶写法②
    • 2、数据校验案例
      • 优化:引入建造者模式
  • 三、源码中的责任链模式
    • 1、FilterChain
    • 2、Netty

一、什么是责任链模式

责任链模式(Chain of Responsibility Patter)也称职责链模式,是将链中每一个节点看做是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。责任链模式属于行为型模式。

1、状态模式与责任链模式的区别

状态模式和责任链模式都能消除if分支过多的问题。但某些情况下,状态模式中的状态可以理解为责任,那么这种情况下,两种模式都可以使用。

从定义来看,状态模式强调的是一个对象内在状态的改变,而责任链模式强调的是外部节点对象间的改变。

从其代码实现上来看,他们间最大的区别就是状态模式各个状态对象知道自己下一个要进入的状态对象;而责任链模式并不清楚其下一个节点处理对象,因为链式组装由客户端负责。

2、责任链模式使用场景

在日常生活中责任链模式还是比较常见的,我们平时处理一些工作,往往是各部分协同合作完成的某一个任务。每个部门都有各自的职责,因此很多时候事情做一半,便会转交给下一个部门;再比如公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名。

责任链模式主要是解耦了请求与处理,客户端只需要将请求发送到链上即可,无需关心请求的具体内容和处理细节,请求会自动进行传递直至有节点对象进行处理。适用于以下应用场景:

  • 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定;
  • 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;
  • 可动态指定一组对象处理请求。

3、责任链模式的优缺点

优点:

  • 降低了对象之间的耦合度:该模式降低了请求发送者和接收者的耦合度。
  • 增强了系统的可扩展性:可以根据需要增加新的请求处理类,满足开闭原则。
  • 增强了给对象指派职责的灵活性:当工作流程发生变化,可以动态地改变链内的成员或者修改它们的次序,也可动态地新增或者删除责任。
  • 责任链简化了对象之间的连接:一个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
  • 责任分担:每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

缺点:

  • 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
  • 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
  • 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

4、责任链模式的角色

在这里插入图片描述
职责链模式主要包含以下角色:

  • 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
  • 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  • 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理;理解责任链模式应当理解的是其模式(道)而不是其具体实现(术),责任链模式的读到支出是其将节点处理者组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动了起来。

二、实例

1、责任链模式的一般写法

责任链模式一般来说有三种写法,一种是传统方式在自身内部定义下一个处理者;还有一种是单独定义一条链,用来关联首尾;还有就是单独定义一条链,使用List进行存放处理者。

这三种写法的效果是一样的,任何一种写法都可以使用其他写法完美平替,使用起来没有任何区别,可以根据场景进行判断。

(1)一般写法

// 抽象处理者
public abstract class Handler {

    protected Handler nextHandler;

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

    public abstract void handleRequest(String request);

}
// 具体处理者
public class ConcreteHandlerA extends Handler {

    public void handleRequest(String request) {
        if ("requestA".equals(request)) {
            System.out.println(this.getClass().getSimpleName() + "deal with request: " + request);
            return;
        }
        if (this.nextHandler != null) {
            this.nextHandler.handleRequest(request);
        }
    }
}
public class ConcreteHandlerB extends Handler {

    public void handleRequest(String request) {
        if ("requestB".equals(request)) {
            System.out.println(this.getClass().getSimpleName() + "deal with request: " + request);
            return;
        }
        if (this.nextHandler != null) {
            this.nextHandler.handleRequest(request);
        }
    }
}
// 测试类
public class Test {
    public static void main(String[] args) {
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();
        handlerA.setNextHanlder(handlerB);
        handlerA.handleRequest("requestB");
    }
}

(2)一般写法-使用建造者模式进阶

上面的Handler加上建造者:

public abstract class Handler {

    protected Handler nextHandler;

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

    public abstract void handleRequest(String request);

    public static class Builder{
        private Handler head;
        private Handler tail;

        public Builder addHandler(Handler handler){
            if (this.head == null) {
                this.head = this.tail = handler;
                return this;
            }
            this.tail.setNextHanlder(handler);
            this.tail = handler;
            return this;
        }

        public Handler build(){
            return this.head;
        }

    }
}
// 测试类
public class Test {
    public static void main(String[] args) {
        Handler.Builder builder = new Handler.Builder();
        builder.addHandler(new ConcreteHandlerA())
                .addHandler(new ConcreteHandlerB())
                .build().handleRequest("requestB");
    }
}

(3)进阶写法①

将Handler使用HandlerChain 统一管理

public abstract class Handler {
  protected Handler successor = null;
  public void setSuccessor(Handler successor) {
    this.successor = successor;
  }
  public final void handle() {
    boolean handled = doHandle();
    if (successor != null && !handled) {
      successor.handle();
    }
  }
  protected abstract boolean doHandle();
}
public class HandlerA extends Handler {
  @Override
  protected boolean doHandle() {
    boolean handled = false;
    //...
    return handled;
  }
}
public class HandlerB extends Handler {
  @Override
  protected boolean doHandle() {
    boolean handled = false;
    //...
    return handled;
  }
}
public class HandlerChain {
  private Handler head = null;
  private Handler tail = null;
  public void addHandler(Handler handler) {
    handler.setSuccessor(null);
    if (head == null) {
      head = handler;
      tail = handler;
      return;
    }
    tail.setSuccessor(handler);
    tail = handler;
  }
  public void handle() {
    if (head != null) {
      head.handle();
    }
  }
}
// 使用举例
public class Application {
  public static void main(String[] args) {
    HandlerChain chain = new HandlerChain();
    chain.addHandler(new HandlerA());
    chain.addHandler(new HandlerB());
    chain.handle();
  }
}

(4)进阶写法②

使用List管理Handler。

public interface IHandler {
  boolean handle();
}
public class HandlerA implements IHandler {
  @Override
  public boolean handle() {
    boolean handled = false;
    //...
    return handled;
  }
}
public class HandlerB implements IHandler {
  @Override
  public boolean handle() {
    boolean handled = false;
    //...
    return handled;
  }
}
public class HandlerChain {
  private List<IHandler> handlers = new ArrayList<>();
  public void addHandler(IHandler handler) {
    this.handlers.add(handler);
  }
  public void handle() {
    for (IHandler handler : handlers) {
      boolean handled = handler.handle();
      if (handled) {
        break;
      }
    }
  }
}
// 使用举例
public class Application {
  public static void main(String[] args) {
    HandlerChain chain = new HandlerChain();
    chain.addHandler(new HandlerA());
    chain.addHandler(new HandlerB());
    chain.handle();
  }
}

2、数据校验案例

来看一段我们经常会写到的代码:

public class MemberService {

    public void login(String loginName,String loginPass){
        if(StringUtils.isEmpty(loginName) ||
                StringUtils.isEmpty(loginPass)){
            System.out.println("用户名和密码为空");
            return;
        }
        System.out.println("用户名和密码不为空,可以往下执行");

        Member member = checkExists(loginName,loginPass);
        if(null == member){
            System.out.println("用户不存在");
            return;
        }
        System.out.println("登录成功!");

        if(!"管理员".equals(member.getRoleName())){
            System.out.println("您不是管理员,没有操作权限");
            return;
        }
        System.out.println("允许操作");

    }

    private Member checkExists(String loginName,String loginPass){
        Member member = new Member(loginName,loginPass);
        member.setRoleName("管理员");
        return member;
    }

    public static void main(String[] args) {
        MemberService service = new MemberService();
        service.login("tom","666");
    }

}

接下来我们使用责任链模式进行优化:

// 创建一个Handler
public abstract class Handler {
    protected Handler next;
    public void next(Handler next){ this.next = next;}

    public abstract void doHandler(Member member);
}
// 具体Handler
public class ValidateHandler extends Handler {
    public void doHandler(Member member) {
        if(StringUtils.isEmpty(member.getLoginName()) ||
                StringUtils.isEmpty(member.getLoginPass())){
            System.out.println("用户名和密码为空");
            return;
        }
        System.out.println("用户名和密码不为空,可以往下执行");
        if(null != next) {
            next.doHandler(member);
        }
    }
}
public class AuthHandler extends Handler {
    public void doHandler(Member member) {
        if(!"管理员".equals(member.getRoleName())){
            System.out.println("您不是管理员,没有操作权限");
            return;
        }
        System.out.println("允许操作");
    }
}
public class LoginHandler extends Handler {
    public void doHandler(Member member) {
        System.out.println("登录成功!");
        member.setRoleName("管理员");
        if(null != next) {
            next.doHandler(member);
        }
    }
}

public class MemberService {

    public void login(String loginName,String loginPass){
        Handler validateHandler = new ValidateHandler();
        Handler loginHandler = new LoginHandler();
        Handler authHandler = new AuthHandler();

        validateHandler.next(loginHandler);
        loginHandler.next(authHandler);

        validateHandler.doHandler(new Member(loginName,loginPass));

    }

}

// 测试类
public class Test {
    public static void main(String[] args) {
        MemberService memberService = new MemberService();
        memberService.login("tom","666");
    }
}

优化:引入建造者模式

因为责任链模式具备链式结构,而上面的代码中,我们看到,组装链式结构的角色是MemberService,当链式结构较长时,MemberService的工作会非常繁琐,并且MemberService代码相对臃肿,且后续 更改处理者或消息类型时,都必须在MemberService中进行修改,不符合开闭原则。产生这些问题的原因就是因为链式结构的组装过于复杂,而对于复杂结构的创建,很自然我们就会想到建造者模式,使用建造者模式,我们完全可以对MemberService指定的处理节点对象进行自动链式组装,客户端只需指定处理节点对象,其他任何事情都无需关心,并且客户指定的处理节点对象顺序不同,构造出来的链式结构也随之不同。

我们改造一下,修改Handler的代码:

public abstract class Handler {
    protected Handler next;
    // 私有化
    private void next(Handler next){ this.next = next;}

    public abstract void doHandler(Member member);

    public static class Builder{
        private Handler head;
        private Handler tail;

        public Builder addHandler(Handler handler){
                if (this.head == null) {
                    this.head = this.tail = handler;
                    return this;
                }
                this.tail.next(handler);
                this.tail = handler;
            return this;
        }

        public Handler build(){
            return this.head;
        }

    }
}

然后修改MemberService的代码:

public class MemberService {

    public void login(String loginName,String loginPass){

        Handler.Builder builder = new Handler.Builder();

        builder.addHandler(new ValidateHandler());
                .addHandler(new LoginHandler())
                .addHandler(new AuthHandler());

        builder.build().doHandler(new Member(loginName,loginPass));
        //用过Netty的人,肯定见过
    }
}

三、源码中的责任链模式

1、FilterChain

在javaWeb应用开发中,FilterChain是职责链(过滤器)模式的典型应用,以下是Filter的模拟实现分析:

// 模拟web请求Request以及web响应Response
public interface Request{
}
public interface Response{
}
// 模拟web过滤器Filter
public interface Filter {
	public void doFilter(Request req,Response res,FilterChain c);
}
// 模拟实现具体过滤器
public class FirstFilter implements Filter {
	@Override
	public void doFilter(Request request, Response response, FilterChain chain) {
		System.out.println("过滤器1 前置处理");
		// 先执行所有request再倒序执行所有response
		chain.doFilter(request, response);
		System.out.println("过滤器1 后置处理");
	}
}
public class SecondFilter implements Filter {
	@Override
	public void doFilter(Request request, Response response, FilterChain chain) {
		System.out.println("过滤器2 前置处理");
		// 先执行所有request再倒序执行所有response
		chain.doFilter(request, response);
		System.out.println("过滤器2 后置处理");
	}
}
// 模拟实现过滤器链FilterChain
public class FilterChain {
	private List<Filter> filters = new ArrayList<Filter>();
	private int index = 0;
	// 链式调用
	public FilterChain addFilter(Filter filter) {
		this.filters.add(filter);
		return this;
	}
	public void doFilter(Request request, Response response) {
		if (index == filters.size()) {
			return;
		}
		Filter filter = filters.get(index);
		index++;
		filter.doFilter(request, response, this);
	}
}
// 测试类
public class Client {
	public static void main(String[] args) {
		Request req = null;
		Response res = null ;
		FilterChain filterChain = new FilterChain();
		filterChain.addFilter(new FirstFilter()).addFilter(new
		SecondFilter());
		filterChain.doFilter(req,res);
	}
}

2、Netty

Netty中非常经典的串行化处理Pipeline就是采用了责任链设计模式。它底层采用双向链表的数据结构,将链上的各个处理器串联起来。客户端每一个请求的到来,Netty都认为Pipeline中的所有的处理器都有机会处理它。因此,对于入站的请求全部从头节点开始往后传播,一直传播到尾结点才会把消息释放掉。

更多Netty源码分析请移步:
Netty核心源码分析(三)业务请求执行关键——ChannelPipeline、ChannelHandler、ChannelHandlerContext源码分析

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nacos配置加载顺序

spring boot 调整日志打印情况 logging:level:com:alibaba:cloud: debug # nacos: debugorg:springframework:context: debugcloud: debug # boot: debug 项目启动时打印了 properties search order:PROPERTIES->JVM->ENV->DEFAULT_SETTING 查看具体代…

股票配资交易系统【实盘】

股票配资系统建设&#xff0c;本文档主要针对实盘股票配资系统。 股票配资交易系统主要包含三部分&#xff1a;App客户端、交易程序服务端、管理后台 App客户端 app客户端是原生应用&#xff0c;非H5生成。客户端主要功能是承接用户的股票订单委托、查询、用户资金转入&#x…

2023.5.12解决Ubuntu中ens33没有ip

在Ubtuntu中的ens33没有ip 如果Ubuntu版本过高 sudo netplan apply如果是Ubuntu 16.04及更早版本 sudo vi /etc/systemd/resolved.conf具体情况如下图所示 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopbac…

java版企业工程项目管理系统 Spring Cloud+Spring Boot+Mybatis+Vue+ElementUI+前后端分离 功能清单

Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目显示…

iVX和其它低代码的平台的区别,“低代码/无代码”分三类

前言 这个图非常认真地对整个“低代码”领域做了严格的分类&#xff0c;这个里面并没有把只针对工作流或单纯BI的工具产品划分进去&#xff0c;主要是这一类&#xff0c;在我个人理解里面更像“SaaS”&#xff0c;也就是增强版SaaS产品&#xff0c;这类产品也主要是给业务人员使…

SpringCloud学习-实用篇04

以下内容的代码可见&#xff1a;SpringCloud_learn/day04 1.初始MQ 同步通讯和异步通讯 微服务间通讯有同步和异步两种方式&#xff0c;同步通讯就像打电话需要实时响应&#xff0c;异步通讯就像发邮件不需要马上回复。两种方式各有优劣&#xff0c;比如打电话能立即得到响应&a…

STM8使用pwm接口调试GDS06灰尘传感器

背景 刚好有项目使用GDS06这款传感器&#xff0c;这里简单做个记录。 GDS06接口如下&#xff0c;这里支持串口和PWM的输出到MCU&#xff0c;由于项目采用STM8S003F3P6&#xff0c;资源极其有限。 所以硬件设计的时候&#xff0c;就考虑采用PWM的接口方式&#xff0c;这样只是…

安科瑞有源电力滤波器的设计原理及应用前景

安科瑞 徐浩竣 江苏安科瑞电器制造有限公司 zx acrelxhj 摘要&#xff1a;该文介绍了有源电力滤波器的工作原理和基本控制方法&#xff0c;并阐述有源电力滤波器的现状及发展前景等等。 关键词&#xff1a;有源电力滤波器&#xff1b;谐波&#xff1b;工作原理&#xff1b;…

方案绞尽脑汁想不出?试试这款AI代写方案

一份计划方案&#xff0c;往往是工作进行下去的核心环节&#xff0c;需要考虑很多因素和变量&#xff0c;在某些情况下&#xff0c;可能没有足够的信息来制定有效的方案。这可能会导致需要额外的研究和调查&#xff0c;以便了解更多关于问题的信息&#xff0c;这将延长制定方案…

侧边拖拉功能

一、页面 <div class"resize-handle" mousedown"startResizing">⋮</div> 二、js data() {return {showSideBar: true,leftPaneWidth: 63, // 左侧区域的初始宽度isResizing: false, // 标记是否正在调整大小startX: 0, // 调整大小开始时的…

Spring AOP 中的切点是什么?如何定义切点?

Spring AOP 中的切点是什么&#xff1f;如何定义切点&#xff1f; 什么是切点&#xff1f; 在 Spring AOP 中&#xff0c;切点&#xff08;Pointcut&#xff09;是指一组连接点&#xff08;Join Point&#xff09;的集合。连接点是程序执行过程中的某个特定点&#xff0c;例如…

初识SpringMVC -- SpringMVC入门保姆级教程(一)

文章目录 前言一、初识SpringMVC1.认识SpringMVC2.SpringMVC入门案例3.SpringMVC开发的一般步骤4.入门案例涉及的知识点5.入门案例工作流程 总结 前言 为了巩固所学的知识&#xff0c;作者尝试着开始发布一些学习笔记类的博客&#xff0c;方便日后回顾。当然&#xff0c;如果能…

阿里云服务器端口怎么打开?详细教程一步步

阿里云服务器端口怎么打开&#xff1f;云服务器ECS端口在安全组中开启&#xff0c;轻量应用服务器端口在防火墙中打开&#xff0c;新手站长以开通80端口为例来详细说下阿里云服务器端口开放图文教程&#xff0c;其他的端口如8080、3306、443、1433也是同样的方法进行开启端口&a…

双轮云台小车实现追踪彩色目标功能

1. 功能说明 在R216a样机上安装一个摄像头&#xff0c;本文示例将实现双轮小车通过二自由度云台自主寻找彩色目标的功能。 2. 结构说明 R216a样机主要是由一个 双轮小车 和一个 2自由度云台 组合而成。 3. 电子硬件 在这个示例中&#xff0c;我们采用了以下硬件&#xff0c;请大…

CRM系统软件不好用有哪些原因?如何选择?

CRM系统的实施也会出现无法落地使用的情况&#xff0c;让CRM系统软件名存实亡。这不仅仅只是个例&#xff0c;很多企业即使投入了很大成本&#xff0c;也不能让CRM系统真正用起来。CRM系统软件用不起来&#xff0c;可以排查这三个原因&#xff0c;教你解决&#xff01; 1.操作…

简单粗暴实现el-input只允许输入数字

<el-input input"phoneNumberphoneNumber.replace(/[^0-9.]/g,)" v-model"phoneNumber" maxlength"11" > </el-input> 如果加入type"number"&#xff0c;会在输入框右侧出现这个恶心的东西 尽管可以使用样式来屏蔽掉 …

基于ArcGIS Pro、Python、USLE、R、INVEST模型等多技术融合的生态系统服务构建生态安全格局

目录 基于ArcGIS Pro、Python、USLE、INVEST模型等多技术融合的生态系统服务构建生态安全格局 第一章 生态安全评价理论及方法介绍 第二章 平台基础 第三章 数据获取与清洗 第四章 基于USLE模型的土壤侵蚀评价 第五章 基于风蚀修正模型的防风固沙功能评估 第六章 水源涵…

联想集团财报:收入持续下滑,联想集团财务前景已恶化

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 联想集团2023财年第三季度财务业绩回顾 联想集团&#xff08;00992&#xff09;于2023年2月16日盘后公布了该公司2023财年第三季度的财报。 财报显示&#xff0c;联想集团的收入已经从2022财年第三季度的201.27亿美元下降到…

西门子PLC如何实现1主多从网口无线通讯

常规来说&#xff0c;多台plc要实现以太网无线连接&#xff0c;首先要先确定以太网线必须正确连接&#xff0c;并建立物理连接。然后需要在PLC端设置好IP地址&#xff0c;以使不同PLC以相同协议可以实现通信交流。最后是建立PLC端数据采集及交换系统&#xff0c;要求在PLC端设置…

一篇必读的物联网平台物模型开发指南,为你解锁未来科技趋势

《高并发系统实战派》-- 值得拥有 文章目录 一、什么是物模型&#xff1f;二、为什么要设计物模型&#xff1f;三、如何设计物模型&#xff1f;设备属性的设计设备服务的设计设备事件的设计 四、物模型案例五、不设计物模型会有什么影响&#xff1f;六、总结 设计物模型可以使物…