Chain of Responsibility

责任链

当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式(Chain of Responsibility Pattern)。

适用性

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

典型情境

邮件从各部门层级依次被处理。
Chain of Responsibility Scenario

结构

Chain of Responsibility Class
Chain of Responsibility Object

Handler - 定义一个处理请求的接口。(可选)实现后继链。
ConcreteHandler - 处理它所负责的请求。可访问它的后继者。如果可处理该请求,就处理之;否则将该请求转发给它的后继者。
Client - 向链上的具体处理者(ConcreteHandler)对象提交请求。

协作:
当客户提交一个请求时,请求沿链传递直至有一个ConcreteHandler对象负责处理它。

实现

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <iostream>
#include <string>
//---------------------------------------------------
class Handler
{
public:
Handler(Handler* suc = 0, std::string word = "No")
{
m_successor = suc;
m_word = word;
}
virtual void handle_request()
{

if (!m_successor) return;
m_successor->handle_request();
}
virtual bool can_handle()
{

return m_word != "No";
}
protected:
Handler* m_successor;
std::string m_word;
};
//---------------------------------------------------
class ConcreteHandlerBottom : public Handler
{
public:
ConcreteHandlerBottom(std::string word = "No") : Handler(0, word)
{}
virtual void handle_request()
{

std::cout<<"ConcreteHandlerBottom has to handle: "<<m_word<<std::endl;
}
};
//---------------------------------------------------
class ConcreteHandler1 : public Handler
{
public:
ConcreteHandler1(Handler* suc = 0, std::string word = "No") : Handler(suc, word)
{}
virtual void handle_request()
{

if (can_handle())
{
std::cout<<"ConcreteHandler1 Handled itself: "<<m_word<<std::endl;
}else
{
std::cout<<"Go to Next Level."<<std::endl;
Handler::handle_request();
}
}
virtual bool can_handle()
{

return m_word == "I'm Second";
}
};
//---------------------------------------------------
class ConcreteHandler2 : public Handler
{
public:
ConcreteHandler2(Handler* suc = 0, std::string word = "No") : Handler(suc, word)
{}
virtual void handle_request()
{

if (can_handle())
{
std::cout<<"ConcreteHandler2 Handled itself: "<<m_word<<std::endl;
}else
{
std::cout<<"Go to Next Level."<<std::endl;
Handler::handle_request();
}
}
virtual bool can_handle()
{

return m_word == "I'm First";
}
};

//---------------------------------------------------
int main()
{

{
std::string msg("Straight to Bottom");
ConcreteHandlerBottom cb(msg);
ConcreteHandler1 c1(&cb, msg);
ConcreteHandler2 c2(&c1, msg);
c2.handle_request();
}
{
std::string msg("I'm Second");
ConcreteHandlerBottom cb(msg);
ConcreteHandler1 c1(&cb, msg);
ConcreteHandler2 c2(&c1, msg);
c2.handle_request();
}
{
std::string msg("I'm First");
ConcreteHandlerBottom cb(msg);
ConcreteHandler1 c1(&cb, msg);
ConcreteHandler2 c2(&c1, msg);
c2.handle_request();
}
system("Pause");
}

优点

  • 将请求的发送者和接受者解耦。
  • 可以简化你的对象,因为它不需要知道链的结构。
  • 通过改变链内的成员或调用它们的次序,允许你动态地新增或者删除责任。

用途和缺点

  • 经常被使用在窗口系统中,处理鼠标和键盘之类的事件。
  • 并不保证请求一定会被执行;如果没有任何对象处理它的话,它可能会落到链尾端之外(这可以是优点也可以是缺点)。
  • 可能不容易观察运行时的特征,有碍于除错。

相关模式

  • 责任链常与Composite一起使用。这种情况下,一个Composite的父Composite可作为它的后继。

[1] 设计模式:可复用面向对象软件的基础
[2] Head First 设计模式