初探职责链模式

代码链接

koonchen/design-patterns/chain-of-responsibility

要点

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

如果我们在一个界面上进行帮助功能的编写,那么非常自然的,我们可以从最特殊的帮助开始编写,同时,我们需要一个对象来处理帮助请求,这里我们请求的对象并不知道最终提供帮助的对象是谁。我们需要一种方法来将他们解耦。

Chain of Responsibility 模式的想法是,给与一条链,链中每一个对象将处理请求,或者将这一请求转发给下一个候选对象,直到该请求被处理并返回给最开始的一个按钮或者其他的提示框。

职责链模式的适用性:

  • 有多个对象可以处理一个请求,而哪个对象处理该请求运行时刻自动确定。
  • 在不明确指定接收者的情况下,向多个对象的其中一个提交请求。
  • 可以处理一个请求的对象集合应被动态指定。

职责链模式的参与者:

  • Handler — 定义一个处理请求的接口。
  • ConcreteHandler — 处理它所负责的请求。
  • Client — 提交请求者。

现在, Chain of Responsibility 模式的结构已经显而易见了:

cover

职责链模式的优缺点:

  • 降低耦合度:接收者和发送者都没有对方明确的信息。
  • 增强了给对象指派职责的灵活性:我们可以在运行时刻对该链进行动态地增加或修改来增加或改变一个请求的职责。
  • 不保证被接受:既然接收者和发送者都不知道对方的存在,所以一个请求可能会因为没有被正确配置二得不到处理。

实现

我们在实现前需要考虑实现问题:

  • 实现后继者链有两种方法:
  • 定义新的链接:通常在 Handler 中定义,但也可由 ConcreteHandlers 来定义。
  • 使用已有的链接:在一个部分 — 整体 的结构中,父构件应用可定义一个部件的后继者,此时窗口组件是已经有了的链接,我们可以直接使用。就像 Composite 模式那样。
  • 连接后继者:Handler 不仅需要定义请求的接口,同时需要维护后继链接,它需要提供一个缺省实现,向后继者转发请求。
  • 表示请求:可以有不同的方法来表示请求,一种是硬编码操作调用,另一种是使用一个处理函数,这个函数以一个请求码为参数。

java 实现

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
72
73
74
75
76
77
enum RequestType {
ConcreteHandler1, ConcreteHandler2
}

class Request {
RequestType requestType;
String requestDescription;

public Request(RequestType requestType, String requestDescription) {
this.requestType = requestType;
this.requestDescription = requestDescription;
}

@Override
public String toString() {
return "Request{" +
"requestType=" + requestType +
", requestDescription='" + requestDescription + '\'' +
'}';
}

public RequestType getRequestType() {
return requestType;
}
}

class Handler {
private Handler next;

public Handler(Handler next) {
this.next = next;
}

void handleRequest(Request request) {
if (next != null) {
next.handleRequest(request);
}
}
}

class ConcreteHandler1 extends Handler {

public ConcreteHandler1(Handler next) {
super(next);
}

@Override
void handleRequest(Request request) {
if (request.getRequestType().equals(RequestType.ConcreteHandler1))
System.out.println("ConcreteHandler1 instance has been created");
else
super.handleRequest(request);
}
}

class ConcreteHandler2 extends Handler {

public ConcreteHandler2(Handler next) {
super(next);
}

@Override
void handleRequest(Request request) {
if (request.getRequestType().equals(RequestType.ConcreteHandler2))
System.out.println("ConcreteHandler2 instance has been created");
else
super.handleRequest(request);
}
}

public class CorClient {
public static void main(String[] args) {
Handler handler = new Handler(new ConcreteHandler1(new ConcreteHandler2(null)));
handler.handleRequest(new Request(RequestType.ConcreteHandler1, "ConcreteHandler1"));
handler.handleRequest(new Request(RequestType.ConcreteHandler2, "ConcreteHandler2"));
}
}

python 实现

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
class Request(object):
def __init__(self, _type):
self._type = _type

class Handler(object):
def __init__(self, _next):
self._next = _next
def handle_request(self, request):
self._next.handle_request(request);

class ConcreteHandler1(Handler):
def handle_request(self, request):
if request._type == 'ConcreteHandler1':
print('ConcreteHandler1 instance has been created')
else:
self._next.handle_request(request)

class ConcreteHandler2(Handler):
def handle_request(self, request):
if request._type == 'ConcreteHandler2':
print('ConcreteHandler2 instance has been created')
else:
self._next.handle_request(request)

class DefaultHandler(Handler):
def __init__(self):
pass
def handle_request(self, request):
print('Without this request type')

if __name__ == '__main__':
handler = ConcreteHandler1(ConcreteHandler2(DefaultHandler()))
handler.handle_request(Request('ConcreteHandler1'))
handler.handle_request(Request('ConcreteHandler2'))
handler.handle_request(Request('ConcreteHandler3'))

职责链模式与 Composite 模式一起使用,这种情况下,一个构件的父构件也可以作为它的后继。