C++设计模式之职责链模式

前言

最近心情很差,因为生活,因为工作;所以想请几天假去丽江玩玩。就向项目经理提交了休假申请,我的项目经理向项目主管提交了我的休假申请,项目主管向部门经理提交了我的休假申请;最后,部门经理同意了我的休假申请。是的,一个简单的休假申请,需要这么复杂的流程,这也是一个公司保证它正常运行的必要。如果部门经理休假了,那么我的休假申请由谁审批呢?这个时候由项目主管代替部门经理进行审批。一个休假申请的审批制度有着严格的要求。而在处理这个请假审批时,各个人员就好比在一条链上的节点,我不知道我的请求由谁审批,但是,我的请求最终会有人来处理的。而这样的一种行为,就好比我今天需要总结的职责链模式一样。

什么是职责链模式?

在GOF的《设计模式:可复用面向对象软件的基础》一书中对职责链模式是这样说的:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,直到有一个对象处理它为止;如下图:

对于每个角色,他们都有他们的职责;当我提交了休假申请时,项目经理需要判断,看看自己能否处理,如果休假超过了2个小时,那么项目经理就不能处理了;项目经理将这个请求提交到项目主管,项目主管判断部门经理在不在,如果部门经理在,项目主管就不能处理了;最后,我的休假申请就到了部门经理那里了,由他亲自审批。可以很明显的看到,项目经理、项目主管和部门经理都有可能处理我的休假申请,我的请求沿着这条链一直走下去,直到有人处理了我的请求。

UML类图

Handler:定义了一个处理请求的接口;其它类如果需要处理相同的请求,可以实现该接口就好了;
ConcreteHandler:处理它所负责的请求,如果可处理该请求,就处理掉这个请求;否则将该请求转发给它的下一个可以处理该请求的对象,所以它必须能访问它的下一个可以处理同样请求的对象;
Client:向处理对象提出具体的请求。

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

使用场合

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

代码实现

代码如下:

#include <iostream>
using namespace std;
 
#define SAFE_DELETE(p) if (p) { delete p; p = NULL; }
 
class HolidayRequest
{
public:
     HolidayRequest(int hour) : m_iHour(hour){}
     int GetHour() { return m_iHour; }
private:
     int m_iHour;
};
 
// The holiday request handler interface
class Manager
{
public:
     virtual bool HandleRequest(HolidayRequest *pRequest) = 0;
};
 
// Project manager
class PM : public Manager
{
public:
     PM(Manager *handler) : m_pHandler(handler){}
     bool HandleRequest(HolidayRequest *pRequest)
     {
          if (pRequest->GetHour() <= 2 || m_pHandler == NULL)
          {
               cout<<"PM said:OK."<<endl;
               return true;
          }
          return m_pHandler->HandleRequest(pRequest);
     }
private:
     Manager *m_pHandler;
};
 
// Department manager
class DM : public Manager
{
public:
     DM(Manager *handler) : m_pHandler(handler){}
     bool HandleRequest(HolidayRequest *pRequest)
     {
          cout<<"DM said:OK."<<endl;
          return true;
     }
 
     // The department manager is in?
     bool IsIn()
     {
          return true;
     }
private:
     Manager *m_pHandler;
};
 
// Project supervisor
class PS : public Manager
{
public:
     PS(Manager *handler) : m_pHandler(handler){}
     bool HandleRequest(HolidayRequest *pRequest)
     {
          DM *pDM = dynamic_cast<DM *>(m_pHandler);
          if (pDM != NULL)
          {
               if (pDM->IsIn())
               {
                    return pDM->HandleRequest(pRequest);
               }
          }
          cout<<"PS said:OK."<<endl;
          return true;
     }
private:
     Manager *m_pHandler;
};
int main()
{
     DM *pDM = new DM(NULL);
     PS *pPS = new PS(pDM);
     PM *pPM = new PM(pPS);
     HolidayRequest *pHolidayRequest = new HolidayRequest(10);
     pPM->HandleRequest(pHolidayRequest);
     SAFE_DELETE(pHolidayRequest);
 
     pHolidayRequest = new HolidayRequest(2);
     pPM->HandleRequest(pHolidayRequest);
 
     SAFE_DELETE(pDM);
     SAFE_DELETE(pPS);
     SAFE_DELETE(pPM);
     SAFE_DELETE(pHolidayRequest);
}

优缺点

1.降低耦合度;职责链模式使得一个对象不用知道是哪一个对象处理它的请求。对象仅需要知道该请求会被正确的处理。接收者和发送者都没有对方的明确的信息,且链中的对象不需要知道链的结构;

2.增强了给对象指派职责的灵活性;当在对象中分派职责时,职责链给你更多的灵活性。你可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的那些职责;

3.不保证被接受,既然一个请求没有明确的接收者,那么就不能保证它一定会被处理;该请求可能一直到链的末端都得不到处理。一个请求也可能因该链没有被正确配置而得不到处理。

总结

职责链模式在实现时,需要处理好它的后继者的问题,就是说,如果我不处理这个请求,那么我将把这个请求发给谁去处理呢?同时,职责链模式在实现时,它的链的形状并不是由职责链本身建立和维护的,而是由客户进行创建的,由客户指定每一个处理者的后继者是谁。这就大大的提高了职责链的灵活性。在实际中,我们也可以将职责链模式与组合模式相结合,一个构件的父构件可以作为它的后继者。

(0)

相关推荐

  • 轻松掌握JavaScript代理模式

    在面向对象设计中,有一个单一职责原则,指就一个类(对象.函数)而言,应该仅有一个引起它变化的原因.如果一个对象承担了过多的职责,就意味着它将变得巨大,引起它变化的原因就多,它把这些职责耦合到了一起,这种耦合会导致程序难于维护和重构. 这时候,我们可以把该对象(本体)的其中一部分职责分离出来给一些第三方对象去做,本体只管自己的一些核心职责,这些第三方对象就称作代理.代理对象可以作为对象(也叫"真正的主体")的保护者,让真正的主体对象做尽量少的工作.在代理设计模式中,一个对象充当了另一个对

  • 轻松掌握JavaScript中介者模式

    中介者模式的作用就是解除对象与对象之间的紧耦合关系,它也称'调停者'.所有的对象都通过中介者对象来通信,而不是相互引用,所以当一个对象发生改变时,只需要通知中介者即可. 如:机场的指挥塔,每架飞机都只需要和指挥塔通信即可,指挥塔知道每架飞机的飞行状况,可以安排所有起降时间,调整航线等 中介者模式符合迪米特法则,即最少知识原则,指一个对象应该尽可能少地了解另外的对象.如果对象之间的耦合性太高,则改变一个对象,会牵动很多对象,难于维护.当对象耦合很紧时,要修改一个对象而不影响其它的对象是很困难的.

  • 深入理解JavaScript系列(38):设计模式之职责链模式详解

    介绍 职责链模式(Chain of responsibility)是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止. 也就是说,请求以后,从第一个对象开始,链中收到请求的对象要么亲自处理它,要么转发给链中的下一个候选者.提交请求的对象并不明确知道哪一个对象将会处理它--也就是该请求有一个隐式的接受者(implicit receiver).根据运行时刻,任一候选者都可以响应相应的请求,候选者的数目是任意

  • 轻松掌握JavaScript享元模式

    在JavaScript中,浏览器特别是移动端的浏览器分配的内存很有限,如何节省内存就成了一件非常有意义的事情.节省内存的一个有效方法是减少对象的数量. 享元模式(Flyweight),运行共享技术有效地支持大量细粒度的对象,避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类). 享元模式可以避免大量非常相似类的开销,在程序设计中,有时需要生产大量细粒度的类实例来表示数据,如果能发现这些实例除了几个参数以外,开销基本相同的话,就可以大幅度较少需要实例化的类的数量.如果能把那些参

  • 轻松掌握JavaScript单例模式

    定义:保证一个对象(类)仅有一个实例,并提供一个访问它的全局访问点: 实现原理:利用闭包来保持对一个局部变量的引用,这个变量保存着首次创建的唯一的实例;  主要用于:全局缓存.登录浮窗等只需要唯一一个实例的时候: 一. 为一个非单例模式对象(如:Demo)实现单例模式的方法:  给Demo添加一个静态方法来实现单例: Demo.getSingle = (function(){ var demo = null; return function(name){ if(!demo){ demo = ne

  • 轻松掌握JavaScript装饰者模式

    在传统的面向对象语言中,给对象添加功能常常使用继承的方式,但继承的方式会带来问题:当父类改变时,他的所有子类都将随之改变. 当JavaScript脚本运行时,在一个对象中(或他的原型上)增加行为会影响该对象的所有实例, 装饰者是一种实现继承的替代方案,它通过重载方法的形式添加新功能,该模式可以在被装饰者前面(before)或者后面(after)加上自己的行为以达到特定的目的. 装饰者模式是为已有功能动态地添加更多功能的一种方式,把每个要装饰的功能放在单独的函数里,然后用该函数包装所要装饰的已有函

  • 轻松掌握JavaScript策略模式

    定义:定义一系列的算法,把它们一个个封装成函数,也可把它们作为属性统一封装进一个对象,然后再定义一个方法,该方法可根据参数自动选择执行对应的算法. 一般用于在实现一个功能时,有很多个方案可选择的情况. 例子1:根据员工薪水salary.绩效等级S.A.B.C,来计算年终奖 //封装了所有算法的策略对象 var strategies = { 'S': function(salary){ return salary*4; }, 'A': function(salary){ return salary

  • JavaScript职责链模式概述

    一.概述 职责链模式(Chain of responsibility),就是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止. 貌似和数据结构中的链表一样. 但,不要搞混了,职责链可不等于链表哦,因为职责链可以在任何一个节点开始往下查找,而链表,则必须从头结点开始往下查找. 比如,DOM事件机制中的冒泡事件就属于职责链,而捕获事件则属于链表. 二.利用职责链模拟冒泡 假设我们有三个对象:li.ul.di

  • php设计模式 Chain Of Responsibility (职责链模式)

    复制代码 代码如下: <?php /** * 职责链模式 * * 为解除请求的发送者和接收者之间的耦合,而使用多个对象都用机会处理这个请求,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它 * */ abstract class Handler { protected $_handler = null; public function setSuccessor($handler) { $this->_handler = $handler; } abstract functio

  • C#职责链模式实例详解

    本文实例讲述了C#职责链模式.分享给大家供大家参考.具体如下: ConcreteHandler1.cs如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { public class ConcreteHandler1:Handler { public override void HandRequest(int

随机推荐