责任链模式

意图

责任链模式(Chain of Responsibility)使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。

将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

与许多其他行为设计模式一样, 责任链会将特定行为转换为被称作处理者的独立对象。 在上述示例中, 每个检查步骤都可被抽取为仅有单个方法的类, 并执行检查操作。 请求及其数据则会被作为参数传递给该方法。

模式建议你将这些处理者连成一条链。 链上的每个处理者都有一个成员变量来保存对于下一处理者的引用。 除了处理请求外, 处理者还负责沿着链传递请求。 请求会在链上移动, 直至所有处理者都有机会对其进行处理。

最重要的是: 处理者可以决定不再沿着链传递请求, 这可高效地取消所有后续处理步骤。

责任链模式结构

现实世界的例子

兽人国王向他的军队发出响亮的命令。最接近反应的是兽人指挥官OrcCommander,然后是兽人军官OrcOfficer,然后是兽人士兵OrcSoldier。指挥官、军官和士兵形成责任链。

用上面的兽人来翻译我们的例子。首先,我们有这样的Request类:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class Request {

/**
* The type of this request, used by each item in the chain to see if they should or can handle
* this particular request.
*/
private final RequestType requestType;

/**
* The name of the request.
*/
private final String name;

/**
* Indicates if the request is handled or not. A request can only switch state from unhandled to
* handled, there's no way to 'unhandle' a request.
*/
private boolean handled;

public Request(RequestType requestType, String name) {
this.requestType = Objects.requireNonNull(requestType);
this.name = Objects.requireNonNull(name);
}

public RequestType getRequestType() {
return requestType;
}

public String getName() {
return name;
}

/**
* Mark the request as handled.
*/
public void markHandled() {
this.handled = true;
}

public boolean isHandled() {
return this.handled;
}

@Override
public String toString() {
return name;
}

}

接下来,是我们请求处理程序的层次结构。

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public interface RequestHandler {

void setNextHandler(RequestHandler handler);

void handle(Request req);

String name();
}

public class OrcCommander implements RequestHandler {

private RequestHandler nextHandler;

@Override
public void setNextHandler(RequestHandler handler) {
this.nextHandler = handler;
}

@Override
public void handle(Request req) {
System.out.println(name() + " handle the request " + req);
this.nextHandler.handle(req);
}

@Override
public String name() {
return "Orc commander";
}
}

public class OrcOfficer implements RequestHandler {

private RequestHandler nextHandler;

@Override
public void setNextHandler(RequestHandler handler) {
this.nextHandler = handler;
}

@Override
public void handle(Request req) {
System.out.println(name() + " handle the request " + req);
this.nextHandler.handle(req);
}

@Override
public String name() {
return "Orc Officer";
}
}

public class OrcSoldier implements RequestHandler {

private RequestHandler nextHandler;

@Override
public void setNextHandler(RequestHandler handler) {
this.nextHandler = handler;
}

@Override
public void handle(Request req) {
System.out.println(name() + " handle the request " + req);
req.markHandled();
}

@Override
public String name() {
return "Orc Soldier";
}
}

兽人国王下达命令并形成请求链。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class OrcKing {

private List<RequestHandler> handlers;

public OrcKing() {
buildRequestChain();
}

private void buildRequestChain() {
handlers = Arrays.asList(new OrcCommander(), new OrcOfficer(), new OrcSoldier());
for (int i = 0; i < handlers.size() - 1; i++) {
handlers.get(i).setNextHandler(handlers.get(i +1));
}
}

/**
* Handle request by the chain.
*/
public void makeRequest(Request req) {
handlers.get(0).handle(req);
}

}

测试:

1
2
3
4
5
6
7
8
public static void main(String[] args) {

Request request = new Request(RequestType.DEFEND_CASTLE, "defend castle");
OrcKing orcKing = new OrcKing();
orcKing.makeRequest(request);

System.out.println(request.isHandled());
}

程序输出:

1
2
3
4
Orc commander handle the request defend castle
Orc Officer handle the request defend castle
Orc Soldier handle the request defend castle
true

优缺点

Responsibility链有下列优点和缺点:

  • 降低耦合度

    该模式使得一个对象无需知道是其他哪一个对象处理其请求。对象仅需知道该请求会被“正确”地处理。

    接收者和发送者都没有对方的明确的信息,且链中的对象不需知道链的结构。

    结果是,职责链可简化对象的相互连接。它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用。

  • 增强了给对象指派职责(Responsibility)的灵活性

    当在对象中分派职责时,职责链给你更多的灵活性。

    你可以通过在运行时刻对该链进行动态的增加或修改来增加或改变处理一个请求的那些职责。你可以将这种机制与静态的特例化处理对象的继承机制结合起来使用。

  • 不保证被接受

    既然一个请求没有明确的接收者,那么就不能保证它一定会被处理—该请求可能一直到链的末端都得不到处理。

    一个请求也可能因该链没有被正确配置而得不到处理。

适合应用场景

  1. 当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式。
    • 该模式能将多个处理者连接成一条链。 接收到请求后, 它会 “询问” 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求。
  2. 当一个请求必须按顺序被多个处理者执行时, 可以使用该模式。
    • 无论你以何种顺序将处理者连接成一条链, 所有请求都会严格按照顺序通过链上的处理者。
  3. 如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式。
    • 如果在处理者类中有对引用成员变量的设定方法, 你将能动态地插入和移除处理者, 或者改变其顺序。

已知使用

  • java.util.logging.Logger#log()
  • Apache Commons Chain
  • javax.servlet.Filter#doFilter()