为方便读者,本文已添加至索引:html
最近时间比较紧,因此发文的速度相对较慢了。可是看到园子里有不少朋友对设计模式感兴趣,我感受很高兴,可以和你们一块儿学习这些知识。算法
以前的文章中,咱们已经介绍了对象建立型和对象结构型的设计模式(请参见索引)。从本篇开始,咱们将接触的是对象行为型设计模式。所谓行为模式涉及到算法和对象间职责的分配。在对象和类的模式以外,还涉及了它们之间的通讯模式。好比咱们今次的主题:Chain of Responsibility(职责链)模式,它就描述了一种请求的传递和响应机制。设计模式
为了能直观地理解职责链模式,咱们将继续采用要点梳理和示例讲解的方式进行。首先来回顾下该系列笔记的主要人物设定(参见Abstract Factory笔记):七个小霍比特人和白雪公主。耳熟能详的故事背景我就很少说了,白雪公主是逃到森林里的。森林里的生活,对于白雪公主而言是艰辛的,她老是得依靠小霍比特人的帮助和照料。七位Hobbits各有所长,譬如会作美味食物的theCook,睿智博学的theWise(参见Adapter模式笔记),勇敢善战的theWarrior(参见Factory Method模式笔记)等等。学习
这和咱们的职责链有何关系?当咱们可爱的白雪公主须要小霍比特人帮助的时候,她可能并不知道谁最终能帮到她。职责链模式正好提供了一种对应的解决方式。它经过给多个对象处理一个请求的机会,从而将提交请求的对象与可能提供解决方案的对象解耦。让咱们举个简单的例子,在森林小屋里白雪公主睡得不踏实,她的床过小了,她想要大一点的床。因而她找到了theWise,向他提出了这个请求。theWise接收了请求,可是他处理不了。因此他接着把公主的请求转达给theWarrior。但theWarrior仍是解决不了,因此他又找来了theWoodCutter(参见Bridge模式笔记)。因而theWoodCutter跑到森林里砍了一大堆木头回来,作了一张很大的床给公主睡。this
在上面所说的例子中,每一个小霍比特人都可以接收公主的请求,而且每一个人都有一个最亲密的伙伴(后继者)。若是他发现本身处理不了这个请求时,他只需简单地把请求转达给亲密的小伙伴(后继者)便可。能够认为,公主的请求在一条霍比特人的关系链上进行传递,直至其中一个对象把它处理掉。从链中第一个对象开始,收到的请求要么亲自处理它,要么转发给链中的下一个候选者。提交请求的对象并不明确地知道哪个对象将会处理它,咱们称该请求有一个隐式的接收者(implicit receiver)。spa
为了进一步理解职责链模式,咱们进行一些要点梳理。设计
一种典型的对象结构code
了解了基本概念以后,让咱们回到前言中所讲的例子。下面将用C++代码来模拟实现其中的职责链。首先,Hobbit类是小霍比特人们的基类:htm
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版本的handleRequest首先会检测本身是否具有该能力,若是没有的话,它将把这个请求转发给后继者。同理,咱们有很是相似的HobbitWoodCutter类:
1 class HobbitWoodCutter : public Hobbit { 2 protected: 3 HobbitWoodCutter(Hobbit* h, int a = ABILITY_CARP); 4 5 virtual void handleRequest(int); 6 } 7 8 HobbitWoodCutter::HobbitWoodCutter(Hobbit* h, int a):Hobbit(h, a) {} 9 10 HobbitWoodCutter::handleRequest(int a) { 11 if (hasAbility(a)) { 12 // handle this request. 13 } else { 14 Hobbit::handleRequest(a); 15 } 16 }
同理还有HobbitWise类等等,下面咱们就建立并链接这些对象以演示前言部分的例子:
1 HobbitWoodCutter* theWoodCutter = new HobbitWoodCutter(0); 2 HobbitWarrior* theWarrior = new HobbitWarrior(theWoodCutter); 3 HobbitWise* theWise = new HobbitWise(theWarrior);
而后白雪公主找到theWise,向他请求一个木工活:
theWise->handleRequest(ABILITY_CARP);
后面发生的事,你们就都知道了。对应于这个例子的UML图以下:
从例子咱们能够看出,白雪公主无需知道小霍比特人之间的联系,她只须要知道,她的请求会获得应有的响应(除了完成请求以外,固然也有可能你们都完不成这个请求)。
用专业的术语表示,职责链模式具备以下优缺点:
职责链模式是一个看起来简单,可是却容易被误解的模式。最多见的误区就是上下级关系这块。事实上职责链并无严格的上下级关系,只是保持一个对后继者的引用而已。后继者能够是它父类的对象,也能够是同级的对象。
今天的笔记就到这里了,欢迎你们批评指正!若是以为能够的话,好文推荐一下,我会很是感谢的!