深入解析责任链模式及其在软件设计中的应用与优势
责任链模型:将能够处理某种类型请求的对象串成一条链,请求沿着链传递,链上的对象逐一判断自己是否有能力处理该请求。这使得多个对象有机会处理请求,从而避免请求被发送。发送者和接收者之间的耦合关系。

(图片来源:设计模式:可重用面向对象软件的基础)
优点:发出请求的客户端并不知道链中的哪个对象最终处理该请求,这使得系统可以动态地重新组织和分配职责,而不会影响客户端。
模式实现
案例:员工请求(休假和加薪)必须得到总监->经理->总经理的批准。
处理程序:
定义一个用于处理请求的接口,具有内置的后继者(可选):
代码语言:javascript
复制
public abstract class Leader {
protected Leader superior;
protected String name;
protected Leader(Leader superior, String name) {
this.superior = superior;
this.name = name;
}
public abstract void handle(Request request);
}
具体处理器
处理它负责的请求,并为其后继者提供访问权限;
如果请求可以被处理,则处理它,否则转发请求:
代码语言:javascript
复制
// 总监
class Director extends Leader {
public Director(Leader superior, String name) {
super(superior, name);
}
@Override
public void handle(Request request) {
if (request.getType().equals("请假") && request.getCount() <= 10) {
System.out.println("[ " + request.getContent() + "] 请假 [" + request.getCount() + "]天, 总监 [" + name + "] 审批通过");
} else {
if (superior != null) {
superior.handle(request);
}
}
}
}
// 经理
class Manager extends Leader {
public Manager(Leader superior, String name) {
super(superior, name);
}
@Override
public void handle(Request request) {
if (request.getType().equals("请假") && request.getCount() <= 20) {
System.out.println("[ " + request.getContent() + "] 请假 [" + request.getCount() + "]天, 经理 [" + name + "] 审批通过");
} else if (request.getType().equals("涨薪") && request.getCount() <= 1000) {
System.out.println("[ " + request.getContent() + "] 涨薪 [" + request.getCount() + "]RMB, 经理 [" + name + "] 审批通过");
} else {
if (superior != null) {
superior.handle(request);
}
}
}
}
// 总经理
class GeneralManager extends Leader {
public GeneralManager(Leader superior, String name) {
super(superior, name);
}
@Override
public void handle(Request request) {
if (request.getType().equals("请假")) {
if (request.getCount() <= 30) {
System.out.println("[ " + request.getContent() + "] 请假 [" + request.getCount() + "]天, 总经理 [" + name + "] 审批通过");
} else {
System.out.println("[ " + request.getContent() + "] 你干脆辞职算了");
}
} else if (request.getType().equals("涨薪")) {
if (request.getCount() <= 10_000) {
System.out.println("[ " + request.getContent() + "] 涨薪 [" + request.getCount() + "]RMB, 总经理 [" + name + "] 审批通过");
} else {
System.out.println("你咋不上天呢");
}
}
}
}
客户
向链上特定的handler对象提交请求:
代码语言:javascript
复制
public class Client {
@Test
public void client() {
Leader generalManger = new GeneralManager(null, "刘备");
Leader manager = new Manager(generalManger, "诸葛亮");
Leader director = new Director(manager, "赵云");
director.handle(new Request("请假", "翡青", 32));
director.handle(new Request("涨薪", "zjf", 1500));
}
}
public class Request {
private String type;
private String content;
private int count;
public Request() {
}
public Request(String type, String content, int count) {
this.type = type;
this.content = content;
this.count = count;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
注:非链表实现了责任链——责任链也可以以集合、数组等形式存储。在很多项目中,每个具体的Handler并不是由开发团队定义的,而是由外部添加的项目上线后的单位。在这种情况下,使用链表方法很难定义责任链。在这种情况下,您可以选择使用集合存储。
概括
优点和缺点
减少耦合:客户端提交请求,请求沿着链传递,直到最终被ConcreteHandler处理。接收方和发送方都没有明确的彼此信息,有利于接收方和发送方的解耦。
增强了为对象分配职责的灵活性:链中的对象本身不知道链结构。他们只维护一个后继指针。因此,责任链可以简化对象的互连,并且可以随时添加或修改处理请求的对象。增强了向对象分配职责的灵活性。
缺陷:无法保证接受:由于请求没有明确的接收者,因此无法保证它会被正确处理,即请求可能直到到达链尾或链序时才会被处理未正确配置。没有“正确”处理。
场景
有多个对象可以处理一种类型的请求,由哪个对象处理是在运行时自动确定的;
向多个对象提交相同的请求,而没有明确指定接收者;
处理请求的对象集合是动态指定的;
Java异常机制:一次try对应多次catch;
Servlet:过滤器链处理;
Spring MVC:拦截器链(具体参见:Spring MVC实践);
相关图案
复合模式:在这种情况下,组件的父组件充当其后继组件。