设计模式——责任链模式

责任链模式定义如下:

使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

责任链模式通用类图

责任链的核心在”链“上,”链“是由多个处理者ConcreteHandler 组成的,其父类Handler 实现如下 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public abstract class Handler {
private Handler nextHandler;

public final Response handleRequest(Request request) {
Response response;
if (this.getHandlerLever().equals(request.getRequestLevel())) {
response = this.doSth(request);
} else {
if (this.nextHandler != null) {
response = this.nextHandler.handleRequest(request);
} else {
System.out.println("handler not found.");
response = null;
}
}
return response;
}

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

protected abstract Level getHandlerLever();

protected abstract Response doSth(Request request);

抽象父类Handler 实现3 个职责:

  1. 定义一个请求的处理方法handleRequest, 唯一对外开放的方法
  2. 定义一个链的编排方法setNext
  3. 定义具体的实现子类必须实现的两个方法:一是自己能够处理的级别getHandlerLever 和具体的业务实现 doSth

下面是三个具体的实现子类:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ConcreteHandler1 extends Handler {
@Override
protected Level getHandlerLever() {
return Level.ONE;
}

@Override
protected Response doSth(Request request) {
String body = request.getBody();
System.out.println("request is: " + body + " I'm handler1" );
return new Response(body);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ConcreteHandler2 extends Handler {
@Override
protected Level getHandlerLever() {
return Level.TWO;
}

@Override
protected Response doSth(Request request) {
String body = request.getBody();
System.out.println("request is: " + body + " I'm handler2");
return new Response(body);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ConcreteHandler3 extends Handler {
@Override
protected Level getHandlerLever() {
return Level.THREE;
}

@Override
protected Response doSth(Request request) {
String body = request.getBody();
System.out.println("request is: " + body + " I'm handler3");
return new Response(body);
}
}

在处理者中涉及三个类:Level类负责定义请求和处理级别,Request类负责封装请 求,Response负责封装链中返回的结果,这三个类都需要根据实际业务来定:

1
2
3
4
public enum Level {
ONE, TWO, THREE;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Request {
private Level level;

private String body;

public Request(Level level, String body) {
this.level = level;
this.body = body;
}

public Level getRequestLevel() {
return this.level;
}

public String getBody() {
return body;
}
}
1
2
3
4
5
6
7
public class Response {
private String message;

public Response(String message) {
this.message = message;
}
}

下面是实际的应用,先构造不同级别的请求,再构造链条,最后用第一个处理器来处理任意一个请求均可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Client {
public static void main(String[] args) {
Request request1 = new Request(Level.ONE, "1");
Request request2 = new Request(Level.TWO, "22");
Request request3 = new Request(Level.THREE, "333");

Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
handler1.setNext(handler2);
handler2.setNext(handler3);

handler1.handleRequest(request2);
handler1.handleRequest(request3);
handler1.handleRequest(request1);
}
}

控制台打印结果:

1
2
3
request is: 22 I'm handler2
request is: 333 I'm handler3
request is: 1 I'm handler1

在实际应用中,一般会有一个封装类对责任模式进行封装,也就是替代Client类,直接 返回链中的第一个处理者,具体链的设置不需要高层次模块关系,这样,更简化了高层次模 块的调用,减少模块间的耦合,提高系统的灵活性。

优点

责任链模式非常显著的优点是将请求和处理分开。请求者可以不用知道是谁处理的,处 理者可以不用知道请求的全貌(例如在J2EE项目开发中,可以剥离出无状态Bean由责任链处 理),两者解耦,提高系统的灵活性。

缺点

责任链有两个非常显著的缺点:一是性能问题,每个请求都是从链头遍历到链尾,特别 是在链比较长的时候,性能是一个非常大的问题。二是调试不很方便,特别是链条比较长, 环节比较多的时候,由于采用了类似递归的方式,调试的时候逻辑可能比较复杂。

链中节点数量需要控制,避免出现超长链的情况,一般的做法是在Handler中设置一个 最大节点数量,在setNext方法中判断是否已经是超过其阈值,超过则不允许该链建立,避免 无意识地破坏系统性能。


设计模式——责任链模式
https://honosv.github.io/2023/09/20/设计模式——责任链模式/
作者
Nova
发布于
2023年9月20日
许可协议