[设计模式] 设计模式之责任链模式【待续】
目录
1 概述
1.1 责任链
责任链模式
(Chain of Responsibility
, CoR、Chain of Command、职责链模式、命令链):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
- 使多个对象都有机会处理请求
请求
在这个链上传递,直到链上的某一个对象决定处理此请求。- 发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。


- 责任链模式是一种行为设计模式:允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。
1.2 现实场景
1.2.1 生产线
-
问题背景
倘若一个系统中有一系列零散的功能节点,它们都负责处理相关的业务,但处理方式又各不相同。
这时客户面对这么一大堆功能节点可能无从下手,根本不知道选择哪个功能节点去提交请求,返回的结果也许只是个半成品,还得再次提交给下一个功能节点,处理过程相当烦琐。
虽然从某种角度看,每个功能节点均承担各自的义务,分工明确、各司其职,但从外部来看则显得毫无组织,团队犹如一盘散沙。
所以为了更高效、更完整地解决客户的问题,各节点一定要发扬团队精神,利用责任链模式组织起来,形成一个有序、有效的业务处理集群,为客户提供更方便、更快捷的服务。 -
汽车生产线的制造流程
以最简单的责任链举例,汽车生产线的制造流程就使用了这种模式:
- 首先,我们进行劳动分工,将汽车零件的安装工作拆分并分配给各安装节点,责任明确划分;
- 然后,架构生产线,将安装节点组织起来,首尾相接,规划操作流程;
- 最终,通过生产线的传递,汽车便从零件到成品得以量产,生产效率大大提升。
我们将汽车生产线从左至右分为3个功能节点,其中:
- A节点负责组装车架、安装车轮;
- B节点负责安装发动机、油箱、传动轴等【内部机件】;
- C节点进行组装外壳、喷漆等美容操作。
这样将产品逐级传递,每经过一个节点就完成一部分工作,最终完成产品交付。
1.2.2 报销审批流程
- 问题背景
生产线的例子其实相对机械、简单,我们来看一个带有一些逻辑的责任链:报销审批流程。
- 报销审批流程
公司为了更高效、安全规范地把控审核工作,通常会将整个审批工作过程按负责人或者工作职责进行拆分,并组织好各个环节中的逻辑关系及走向,最终形成标准化的审批流程,如图所示。
-
审批流程需要依次通过财务专员、财务经理、财务总监的审批。
-
如果申请金额在审批人的审批职权范围内,则:审批通过并终止流程;反之,则:会升级至更高层级的上级去继续审批;
-
直至最终的财务总监,如果仍旧超出财务总监的审批金额,则:驳回申请,流程终止。
-
需求
假设我们正在开发一款办公系统,系统有个模块是审批,起初审批只有一级审批,直接提交,主管进行审批即可。
随着时间推移,人员越来越多,公司的组织架构也在扩大。审批的请求自然也多了。
于是要将审批按照金额进行划分审核人员,超过金额数就上级进行审批,比如: -
100元以内 => 财务专员审批即可,否则将由财务组长审批
-
1000以内 => 财务组长审批即可,否则将由财务主管审批
-
10000以内 => 财务主管审批即可,否则不通过(或者交由老板审批)
2 模式定义
责任链模式涉及到的角色如下所示:
抽象处理者
(Handler
)角色:定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。Handler类的聚合关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操作。具体处理者
(ConcreteHandler
)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
3 主要角色
4 通用代码
5 模式特点/适用场景
6 案例分析
日志器
Logger
import java.util.*;
public abstract class Logger {
public static int ERR = 3;
public static int NOTICE = 5;
public static int DEBUG = 7;
protected int mask;
// The next element in the chain of responsibility
protected Logger next;
public Logger setNext( Logger l) {
next = l;
return this;
}
public final void message( String msg, int priority ) {
if ( priority <= mask ) {
writeMessage( msg );
if ( next != null ) {
next.message( msg, priority );
}
}
}
protected abstract void writeMessage( String msg );
}
StdoutLogger
public class StdoutLogger extends Logger {
public StdoutLogger( int mask ) {
this.mask = mask;
}
protected void writeMessage( String msg ) {
System.out.println( "Writting to stdout: " + msg );
}
}
EmailLogger
public class EmailLogger extends Logger {
public EmailLogger( int mask ) { this.mask = mask; }
protected void writeMessage( String msg ) {
System.out.println( "Sending via email: " + msg );
}
}
StderrLogger
public class StderrLogger extends Logger {
public StderrLogger( int mask ) {
this.mask = mask;
}
protected void writeMessage( String msg ) {
System.out.println( "Sending to stderr: " + msg );
}
}
[client] ChainOfResponsibilityExample
public class ChainOfResponsibilityExample {
public static void main( String[] args ){
// Build the chain of responsibility
Logger l = new StdoutLogger( Logger.DEBUG).setNext(
new EmailLogger( Logger.NOTICE ).setNext(
new StderrLogger( Logger.ERR )
)
);
// Handled by StdoutLogger
l.message( "Entering function y.", Logger.DEBUG );
// Handled by StdoutLogger and EmailLogger
l.message( "Step1 completed.", Logger.NOTICE );
// Handled by all three loggers
l.message( "An error has occurred.", Logger.ERR );
}
}
X 参考文献

本文链接: https://www.cnblogs.com/johnnyzen/p/17214556.html
关于博文:评论和私信会在第一时间回复,或直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
日常交流:大数据与软件开发-QQ交流群: 774386015 【入群二维码】参见左下角。您的支持、鼓励是博主技术写作的重要动力!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
2019-03-14 [Linux] shell编程之判断文件类型
2019-03-14 [Linux] shell编程之数组操作
2019-03-14 [Linux] shell编程之求命令行中所有整数之和