责任链
当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式(Chain of Responsibility Pattern)。
适用性
- 有多个对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
- 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
- 可处理一个请求的对象集合应被动态指定。
典型情境
邮件从各部门层级依次被处理。
结构
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 设计模式