[学习笔记]设计模式之Chain of Responsibility(一)

2014-11-24 00:41:44 · 作者: · 浏览: 0
最近时间比较紧,所以发文的速度相对较慢了。但是看到园子里有很多朋友对设计模式感兴趣,我感觉很高兴,能够和大家一起学习这些知识。
之前的文章中,我们已经介绍了对象创建型和对象结构型的设计模式(请参见索引)。从本篇开始,我们将接触的是对象行为型设计模式。所谓行为模式涉及到算法和对象间职责的分配。在对象和类的模式之外,还涉及了它们之间的通信模式。比如我们今次的主题:Chain of Responsibility(职责链)模式,它就描述了一种请求的传递和响应机制。
为了能直观地理解职责链模式,我们将继续采用要点梳理和示例讲解的方式进行。首先来回顾下该系列笔记的主要人物设定(参见Abstract Factory笔记):七个小霍比特人和白雪公主。耳熟能详的故事背景我就不多说了,白雪公主是逃到森林里的。森林里的生活,对于白雪公主而言是艰辛的,她总是得依靠小霍比特人的帮助和照料。七位Hobbits各有所长,譬如会做美味食物的theCook,睿智博学的theWise(参见Adapter模式笔记),勇敢善战的theWarrior(参见Factory Method模式笔记)等等。
这和我们的职责链有何关系?当我们可爱的白雪公主需要小霍比特人帮助的时候,她可能并不知道谁最终能帮到她。职责链模式正好提供了一种对应的解决方式。它通过给多个对象处理一个请求的机会,从而将提交请求的对象与可能提供解决方案的对象解耦。让我们举个简单的例子,在森林小屋里白雪公主睡得不踏实,她的床太小了,她想要大一点的床。于是她找到了theWise,向他提出了这个请求。theWise接收了请求,但是他处理不了。所以他接着把公主的请求转达给theWarrior。但theWarrior还是解决不了,所以他又找来了theWoodCutter(参见Bridge模式笔记)。于是theWoodCutter跑到森林里砍了一大堆木头回来,做了一张很大的床给公主睡。
在上面所说的例子中,每个小霍比特人都能够接收公主的请求,并且每个人都有一个最亲密的伙伴(后继者)。如果他发现自己处理不了这个请求时,他只需简单地把请求转达给亲密的小伙伴(后继者)即可。可以认为,公主的请求在一条霍比特人的关系链上进行传递,直至其中一个对象把它处理掉。从链中第一个对象开始,收到的请求要么亲自处理它,要么转发给链中的下一个候选者。提交请求的对象并不明确地知道哪一个对象将会处理它,我们称该请求有一个隐式的接收者(implicit receiver)。
为了进一步理解职责链模式,我们进行一些要点梳理。
要点梳理
目的分类
对象行为型模式
范围准则
对象(该模式处理对象间的关系,这些关系在运行时刻是可以变化的,更具动态性)
主要功能
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
适用情况
有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
我们想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
可处理一个请求的对象集合应被动态指定。
参与部分
Handler:定义一个处理请求的接口;(可选)实现后继链
ConcreteHandler:处理它所负责的请求;可访问它的后继者;如果可处理该请求,就处理之;否则将该请求转发给它的后继者
Client:向链上的ConcreteHandler对象提交请求
协作过程
当客户提交一个请求时,请求沿链传递直至有一个ConcreteHandler对象负责处理它。
UML图
一种典型的对象结构
示例分析 - 有困难找我们
了解了基本概念之后,让我们回到前言中所讲的例子。下面将用C++代码来模拟实现其中的职责链。首先,Hobbit类是小霍比特人们的基类:
复制代码
1 #define ABILITY_COOK 1
2 #define ABILITY_FIGHT 2
3 #define ABILITY_CARP 3
4 #define ABILITY_KNOWLEDGE 4
5 // ... other ability types ...
6
7 class Hobbit {
8 public:
9 Hobbit(Hobbit* h = 0, int a = 0);
10
11 virtual bool hasAbility(int);
12 virtual void handleRequest(int);
13 private:
14 Hobbit* _successor; // the intimate friend.
15 int _ability;
16 };
复制代码
它定义了处理请求的接口handleRequest,同时也保持了对象链中它的后继者的引用_successor(也就是前文所指的最亲密的小伙伴)。它还维护一个_ability,代表这个小霍比特人的最擅长能力。handleRequest是最关键的操作,它可以被子类重定义,这里默认是传递给后继者去处理。hasAbility则是一个辅助操作,用于判断对象是否具备相应的能力。
复制代码
1 Hobbit::Hobbit(Hobbit* h, int a): _successor(h), _ability(a) {}
2
3 bool Hobbit::hasAbility(int a) {
4 return _ability == a;
5 }
6
7 void Hobbit::handleRequest() {
8 if (_successor !=0) {
9 _successor->handleRequest();
10 }
11 }
复制代码
theWarrior是HobbitWarrior类的实例对象,而HobbitWarrior则是Hobbit的子类:
复制代码
1 class HobbitWarrior : public Hobbit {
2 protected:
3 HobbitWarrior(Hobbit* h, int a = ABILITY_FIGHT);
4
5 virtual void handleRequest(int);
6 }
7
8 HobbitWarrior::HobbitWarrior(Hobbit* h, int a):Hobbit(h, a) {}
9
10 HobbitWarrior::handleRequest(int a) {
11 if (hasAbility(a)) {
12 // handle this request.
13 } else {
14 Hobbit::handleRequest(a);
15 }
16 }
复制代码
在这里,HobbitWarrior版本的