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

为方便读者,本文已添加至索引:html

写在前面

最近时间比较紧,因此发文的速度相对较慢了。可是看到园子里有不少朋友对设计模式感兴趣,我感受很高兴,可以和你们一块儿学习这些知识。算法

以前的文章中,咱们已经介绍了对象建立型对象结构型的设计模式(请参见索引)。从本篇开始,咱们将接触的是对象行为型设计模式。所谓行为模式涉及到算法和对象间职责的分配。在对象和类的模式以外,还涉及了它们之间的通讯模式。好比咱们今次的主题:Chain of Responsibility(职责链)模式,它就描述了一种请求的传递和响应机制。设计模式

为了能直观地理解职责链模式,咱们将继续采用要点梳理和示例讲解的方式进行。首先来回顾下该系列笔记的主要人物设定(参见Abstract Factory笔记):七个小霍比特人和白雪公主。耳熟能详的故事背景我就很少说了,白雪公主是逃到森林里的。森林里的生活,对于白雪公主而言是艰辛的,她老是得依靠小霍比特人的帮助和照料。七位Hobbits各有所长,譬如会作美味食物的theCook,睿智博学的theWise(参见Adapter模式笔记),勇敢善战的theWarrior(参见Factory Method模式笔记)等等。学习

这和咱们的职责链有何关系?当咱们可爱的白雪公主须要小霍比特人帮助的时候,她可能并不知道谁最终能帮到她。职责链模式正好提供了一种对应的解决方式。它经过给多个对象处理一个请求的机会,从而将提交请求的对象与可能提供解决方案的对象解耦。让咱们举个简单的例子,在森林小屋里白雪公主睡得不踏实,她的床过小了,她想要大一点的床。因而她找到了theWise,向他提出了这个请求。theWise接收了请求,可是他处理不了。因此他接着把公主的请求转达给theWarrior。但theWarrior仍是解决不了,因此他又找来了theWoodCutter(参见Bridge模式笔记)。因而theWoodCutter跑到森林里砍了一大堆木头回来,作了一张很大的床给公主睡。this

在上面所说的例子中,每一个小霍比特人都可以接收公主的请求,而且每一个人都有一个最亲密的伙伴(后继者)。若是他发现本身处理不了这个请求时,他只需简单地把请求转达给亲密的小伙伴(后继者)便可。能够认为,公主的请求在一条霍比特人的关系链上进行传递,直至其中一个对象把它处理掉。从链中第一个对象开始,收到的请求要么亲自处理它,要么转发给链中的下一个候选者。提交请求的对象并不明确地知道哪个对象将会处理它,咱们称该请求有一个隐式的接收者(implicit receiver)spa

为了进一步理解职责链模式,咱们进行一些要点梳理。设计

要点梳理

  • 目的分类
    • 对象行为型模式
  • 范围准则
    • 对象(该模式处理对象间的关系,这些关系在运行时刻是能够变化的,更具动态性)
  • 主要功能
    • 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
  • 适用状况
    • 有多个的对象能够处理一个请求,哪一个对象处理该请求运行时刻自动肯定。
    • 咱们想在不明确指定接收者的状况下,向多个对象中的一个提交一个请求。
    • 可处理一个请求的对象集合应被动态指定。
  • 参与部分
    • Handler:定义一个处理请求的接口;(可选)实现后继链
    • ConcreteHandler:处理它所负责的请求;可访问它的后继者;若是可处理该请求,就处理之;不然将该请求转发给它的后继者
    • Client:向链上的ConcreteHandler对象提交请求
  • 协做过程
    • 当客户提交一个请求时,请求沿链传递直至有一个ConcreteHandler对象负责处理它。
  • UML图

一种典型的对象结构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图以下:

特色总结

从例子咱们能够看出,白雪公主无需知道小霍比特人之间的联系,她只须要知道,她的请求会获得应有的响应(除了完成请求以外,固然也有可能你们都完不成这个请求)。

用专业的术语表示,职责链模式具备以下优缺点:

  1. 下降耦合度。该模式使得一个对象无需知道是其余哪个对象处理其请求。接收者和发送者都没有对方的明确的信息,且链中的对象不需知道链的结构。这样一来,职责链简化了对象的相互链接。它们仅需保持一个指向其后继者的引用,而不需保持它全部的候选接受者的引用。
  2. 加强了给对象指派职责Responsibility的灵活性。咱们能够经过在运行时刻对该链进行动态的增长或修改来增长或改变处理一个请求的那些职责,这给咱们更大的灵活性。
  3. 缺点就是不保证被处理。既然一个请求没有明确的接收者,那么就不能保证它必定会被处理,该请求可能一直到链的末端都得不处处理。一个请求也可能因该链没有被正确配置而得不处处理。

职责链模式是一个看起来简单,可是却容易被误解的模式。最多见的误区就是上下级关系这块。事实上职责链并无严格的上下级关系,只是保持一个对后继者的引用而已。后继者能够是它父类的对象,也能够是同级的对象。

写在最后

今天的笔记就到这里了,欢迎你们批评指正!若是以为能够的话,好文推荐一下,我会很是感谢的!

相关文章
相关标签/搜索