前言
在公司请年假的时候,需要首先在TMS系统提出申请,在提出申请的时候,发现申请不同的时间长短,审批的领导不一样,如不超过但是包括1天由科长(Section Chief)审批,超过1天但是不超过3天由部长(Minister)审批,超过3天以上由主任(Director)审批。在这个审批流程中,我们的年假请求沿着一条链在传递,每个请求处理者都根据请求的具体情况在自己的处理范围内进行审批,有一种专门用于处理这种请求链式传递的模式,它就是本章将要介绍的职责链模式。
责任链模式
意图 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止
常用的对象行为型设计模式之一,职责链可以是一条直线、一个环或者一个树形结构,最常见的职责链是直线型,即沿着一条单向的链来传递请求。链上的每一个对象都是请求处理者,职责链模式可以将请求的处理者组织成一条链,并让请求沿着链传递,由链上的处理者对请求进行相应的处理,客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到链上即可,实现请求发送者和请求处理者解耦
参与者
Handler 抽象处理者,定义了一个处理请求的接口,不同的具体处理者处理请求的实现不同 一般还包含一个抽象处理者的对象,作为其下家的引用。通过该引用,处理者可以连成一条链
ConcreteHandler 具体处理者,抽象处理者的子类,处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法 处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者(具体处理者中可以访问链中下一个对象,以便请求的转发) 具体处理者有两大作用:处理请求 & 转发请求
Client 客户端,负责创建职责链,向链上的具体处理者(ConcreteHandler)对象提交请求
模式结构
代码实现 1.首先定义抽象的Handler
,并提供HandlerRequest()
接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 class Handler{ protected: Handler *m_pHandler; int m_nState; public: Handler(Handler * pHandler ) : m_pHandler(pHandler ) {}; public: virtual void HandlerRequest(int nState ) = 0 ; };
2.再分别定义Handler
类的三个具体处理子类,并实现其中的HandlerRequest()
接口,该接口主要作用是处理该请求或转发请求给下个处理者:
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 #define NULL_POINTER(ptr ) (NULL == ptr) class ConcreteHandlerA : public Handler{ public: ConcreteHandlerA(Handler * pHandler ) : Handler(pHandler ) {}; public: virtual void HandlerRequest(int nState ) { if (nState < 10 ) { cout << "Concrete Handler A Do The Request !!!" << "State: " << nState << endl; return; } if (NULL_POINTER(m_pHandler ) ) { cout << "No Handler Do The Request !!!" << "State: " << nState << endl; return; } m_pHandler->HandlerRequest(nState ) ; } }; class ConcreteHandlerB : public Handler{ public: ConcreteHandlerB(Handler * pHandler ) : Handler(pHandler ) {}; public: virtual void HandlerRequest(int nState ) { if (nState < 20 ) { cout << "Concrete Handler B Do The Request !!!" << "State: " << nState << endl; return; } if (NULL_POINTER(m_pHandler ) ) { cout << "No Handler Do The Request !!!" << "State: " << nState << endl; return; } m_pHandler->HandlerRequest(nState ) ; } }; class ConcreteHandlerC : public Handler{ public: ConcreteHandlerC(Handler * pHandler ) : Handler(pHandler ) {}; public: virtual void HandlerRequest(int nState ) { if (nState < 30 ) { cout << "Concrete Handler C Do The Request !!!" << "State: " << nState << endl; return; } if (NULL_POINTER(m_pHandler ) ) { cout << "No Handler Do The Request !!!" << "State: " << nState << endl; return; } m_pHandler->HandlerRequest(nState ) ; } };
3.测试责任链模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #define SAFE_RELASE_POINTER(ptr ) if (!NULL_POINTER(ptr ) ) {delete ptr; ptr = NULL;} void ResponseTest_General() { Handler *pCHC = new ConcreteHandlerC(NULL) ; Handler *pCHB = new ConcreteHandlerB(pCHC ) ; Handler *pCHA = new ConcreteHandlerA(pCHB ) ; pCHA->HandlerRequest(5) ; pCHA->HandlerRequest(15) ; pCHA->HandlerRequest(25) ; pCHA->HandlerRequest(35) ; SAFE_RELASE_POINTER(pCHA ) ; SAFE_RELASE_POINTER(pCHB ) ; SAFE_RELASE_POINTER(pCHC ) ; }
4.运行结果:
Concrete Handler A Do The Request !!!State: 5
Concrete Handler B Do The Request !!!State: 15
Concrete Handler C Do The Request !!!State: 25
No Handler Do The Request !!!State: 35
责任链模式的分类 责任链模式根据请求是否能同时被多个处理对象处理或者请求是否能最终不被任何请求者处理,分为以下两类:
纯的责任链模式
一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后又将责任向下传递的情况
要求一个请求必须被某一个处理者对象所接收,不能出现某个请求未被任何一个处理者对象处理的情况
不纯的职责链模式
一个不纯的职责链模式中允许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求
而且一个请求可以最终不被任何处理者对象所接收
事件浮升(Event Bubbling)机制:在GUI组件的事件处理机制中,当事件发生在某一个组件时候,先通过组件对象的handleEvent()方法将事件传递给相应的事件处理方法,该事件处理方法将处理此事件,然后决定是否将该事件向上一级容器组件传播;上级容器组件在接到事件之后可以继续处理此事件并决定是否继续向上级容器组件传播,如此反复,直到事件到达顶层容器组件为止;如果一直传到最顶层容器仍没有处理方法,则该事件不予处理。 在这种场景中,每一级组件在接收到事件时,都可以处理此事件,而不论此事件是否在上一级已得到处理,还存在事件未被处理的情况
使用场景
有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定,客户端只需将请求提交到链上,而无须关心请求的处理对象是谁以及它是如何处理的
在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
可动态指定一组对象处理请求,客户端可以动态创建职责链来处理请求,还可以改变链中处理者之间的先后次序
优缺点
优点
职责链模式使得一个对象无须知道是其他哪一个对象处理其请求,对象仅需知道该请求会被处理即可,接收者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度
请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接
在给对象分派职责时,职责链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责
缺点
如果建链不当,可能会造成循环调用,将导致系统陷入死循环
由于一个请求没有明确的接收者,那么就不能保证它一定会被处理,该请求可能一直到链的末端都得不到处理;一个请求也可能因职责链没有被正确配置而得不到处理
责任链模式具体实例
请假审批问题 使用责任链模式简单实现前言所述的请假审批过程
代码实现 1.定义抽象的HoliadyHandler
类,并提供HandleHolidayRequest
接口:
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 class HolidayRequest{ private : string _type; int _days; public: HolidayRequest(string type , int days ) : _type(type ) , _days(days ) {}; public: string getType(void ) { return _type; } int getDays(void ) { return _days; } }; class HoliadyHandler{ protected: HoliadyHandler *_handler; public: HoliadyHandler() : _handler(NULL) {}; public: void setHandler(HoliadyHandler * handler ) { _handler = handler; } public: virtual void HandleHolidayRequest(HolidayRequest &request ) = 0 ; };
2.分别定义处理者HolidayRequest
的子类SectionChief
和Minister
及Director
:
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 class SectionChief : public HoliadyHandler{ private : string _name; public: SectionChief(string name ) : _name(name ) {}; public: void HandleHolidayRequest(HolidayRequest &request ) { if (request.getDays() <= 1 ) { cout << "Section chief " << _name << " approve your " << request.getDays() << " days for " << request.getType() << " request !" << endl; } else { if (NULL_POINTER(_handler ) ) { cout << "No holiday handler is assigned !" << endl; } else { _handler->HandleHolidayRequest(request ) ; } } } }; class Minister : public HoliadyHandler{ private : string _name; public: Minister(string name ) : _name(name ) {}; public: void HandleHolidayRequest(HolidayRequest &request ) { if (request.getDays() <= 3 ) { cout << "Minister " << _name << " approve your " << request.getDays() << " days for " << request.getType() << " request !" << endl; } else { if (NULL_POINTER(_handler ) ) { cout << "No holiday handler is assigned !" << endl; } else { _handler->HandleHolidayRequest(request ) ; } } } }; class Director : public HoliadyHandler{ private : string _name; public: Director(string name ) : _name(name ) {}; public: void HandleHolidayRequest(HolidayRequest &request ) { if (request.getDays() > 3 ) { cout << "Director " << _name << " approve your " << request.getDays() << " days for " << request.getType() << " request !" << endl; } else { if (NULL_POINTER(_handler ) ) { cout << "No holiday handler is assigned !" << endl; } else { _handler->HandleHolidayRequest(request ) ; } } } };
3.测试责任链模式:
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 void ResponseTest_Holiday() { HoliadyHandler *pD = new Director("john" ) ; HoliadyHandler *pM = new Minister("bob" ) ; HoliadyHandler *pS = new SectionChief("bill" ) ; pS->setHandler(pM ) ; pM->setHandler(pD ) ; pD->setHandler(NULL) ; HolidayRequest request1("dragon boat festival" , 1 ); HolidayRequest request2("mid-autumn festival" , 2 ); HolidayRequest request3("spring festival" , 3 ); HolidayRequest request4("spring festival" , 4 ); pS->HandleHolidayRequest(request1 ) ; pS->HandleHolidayRequest(request2 ) ; pS->HandleHolidayRequest(request3 ) ; pS->HandleHolidayRequest(request4 ) ; SAFE_RELASE_POINTER(pD ) ; SAFE_RELASE_POINTER(pM ) ; SAFE_RELASE_POINTER(pS ) ; }
4.运行结果:
Section chief bill approve your 1 days for dragon boat festival request !
Minister bob approve your 2 days for mid-autumn festival request !
Minister bob approve your 3 days for spring festival request !
Director john approve your 4 days for spring festival request !--
title: 责任链模式(行为型) date: 2016-4-20 categories: Design Pattern tags:
Design Pattern
Behavior Pattern
前言
在公司请年假的时候,需要首先在TMS系统提出申请,在提出申请的时候,发现申请不同的时间长短,审批的领导不一样,如不超过但是包括1天由科长(Section Chief)审批,超过1天但是不超过3天由部长(Minister)审批,超过3天以上由主任(Director)审批。在这个审批流程中,我们的年假请求沿着一条链在传递,每个请求处理者都根据请求的具体情况在自己的处理范围内进行审批,有一种专门用于处理这种请求链式传递的模式,它就是本章将要介绍的职责链模式。
责任链模式
意图 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止
常用的对象行为型设计模式之一,职责链可以是一条直线、一个环或者一个树形结构,最常见的职责链是直线型,即沿着一条单向的链来传递请求。链上的每一个对象都是请求处理者,职责链模式可以将请求的处理者组织成一条链,并让请求沿着链传递,由链上的处理者对请求进行相应的处理,客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到链上即可,实现请求发送者和请求处理者解耦
参与者
Handler 抽象处理者,定义了一个处理请求的接口,不同的具体处理者处理请求的实现不同 一般还包含一个抽象处理者的对象,作为其下家的引用。通过该引用,处理者可以连成一条链
ConcreteHandler 具体处理者,抽象处理者的子类,处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法 处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者(具体处理者中可以访问链中下一个对象,以便请求的转发) 具体处理者有两大作用:处理请求 & 转发请求
Client 客户端,负责创建职责链,向链上的具体处理者(ConcreteHandler)对象提交请求
模式结构
代码实现 1.首先定义抽象的Handler
,并提供HandlerRequest()
接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 class Handler{ protected: Handler *m_pHandler; int m_nState; public: Handler(Handler * pHandler ) : m_pHandler(pHandler ) {}; public: virtual void HandlerRequest(int nState ) = 0 ; };
2.再分别定义Handler
类的三个具体处理子类,并实现其中的HandlerRequest()
接口,该接口主要作用是处理该请求或转发请求给下个处理者:
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 #define NULL_POINTER(ptr ) (NULL == ptr) class ConcreteHandlerA : public Handler{ public: ConcreteHandlerA(Handler * pHandler ) : Handler(pHandler ) {}; public: virtual void HandlerRequest(int nState ) { if (nState < 10 ) { cout << "Concrete Handler A Do The Request !!!" << "State: " << nState << endl; return; } if (NULL_POINTER(m_pHandler ) ) { cout << "No Handler Do The Request !!!" << "State: " << nState << endl; return; } m_pHandler->HandlerRequest(nState ) ; } }; class ConcreteHandlerB : public Handler{ public: ConcreteHandlerB(Handler * pHandler ) : Handler(pHandler ) {}; public: virtual void HandlerRequest(int nState ) { if (nState < 20 ) { cout << "Concrete Handler B Do The Request !!!" << "State: " << nState << endl; return; } if (NULL_POINTER(m_pHandler ) ) { cout << "No Handler Do The Request !!!" << "State: " << nState << endl; return; } m_pHandler->HandlerRequest(nState ) ; } }; class ConcreteHandlerC : public Handler{ public: ConcreteHandlerC(Handler * pHandler ) : Handler(pHandler ) {}; public: virtual void HandlerRequest(int nState ) { if (nState < 30 ) { cout << "Concrete Handler C Do The Request !!!" << "State: " << nState << endl; return; } if (NULL_POINTER(m_pHandler ) ) { cout << "No Handler Do The Request !!!" << "State: " << nState << endl; return; } m_pHandler->HandlerRequest(nState ) ; } };
3.测试责任链模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #define SAFE_RELASE_POINTER(ptr ) if (!NULL_POINTER(ptr ) ) {delete ptr; ptr = NULL;} void ResponseTest_General() { Handler *pCHC = new ConcreteHandlerC(NULL) ; Handler *pCHB = new ConcreteHandlerB(pCHC ) ; Handler *pCHA = new ConcreteHandlerA(pCHB ) ; pCHA->HandlerRequest(5) ; pCHA->HandlerRequest(15) ; pCHA->HandlerRequest(25) ; pCHA->HandlerRequest(35) ; SAFE_RELASE_POINTER(pCHA ) ; SAFE_RELASE_POINTER(pCHB ) ; SAFE_RELASE_POINTER(pCHC ) ; }
4.运行结果:
Concrete Handler A Do The Request !!!State: 5
Concrete Handler B Do The Request !!!State: 15
Concrete Handler C Do The Request !!!State: 25
No Handler Do The Request !!!State: 35
责任链模式的分类 责任链模式根据请求是否能同时被多个处理对象处理或者请求是否能最终不被任何请求者处理,分为以下两类:
纯的责任链模式
一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后又将责任向下传递的情况
要求一个请求必须被某一个处理者对象所接收,不能出现某个请求未被任何一个处理者对象处理的情况
不纯的职责链模式
一个不纯的职责链模式中允许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求
而且一个请求可以最终不被任何处理者对象所接收
事件浮升(Event Bubbling)机制:在GUI组件的事件处理机制中,当事件发生在某一个组件时候,先通过组件对象的handleEvent()方法将事件传递给相应的事件处理方法,该事件处理方法将处理此事件,然后决定是否将该事件向上一级容器组件传播;上级容器组件在接到事件之后可以继续处理此事件并决定是否继续向上级容器组件传播,如此反复,直到事件到达顶层容器组件为止;如果一直传到最顶层容器仍没有处理方法,则该事件不予处理。 在这种场景中,每一级组件在接收到事件时,都可以处理此事件,而不论此事件是否在上一级已得到处理,还存在事件未被处理的情况
使用场景
有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定,客户端只需将请求提交到链上,而无须关心请求的处理对象是谁以及它是如何处理的
在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
可动态指定一组对象处理请求,客户端可以动态创建职责链来处理请求,还可以改变链中处理者之间的先后次序
优缺点
优点
职责链模式使得一个对象无须知道是其他哪一个对象处理其请求,对象仅需知道该请求会被处理即可,接收者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度
请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接
在给对象分派职责时,职责链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责
缺点
如果建链不当,可能会造成循环调用,将导致系统陷入死循环
由于一个请求没有明确的接收者,那么就不能保证它一定会被处理,该请求可能一直到链的末端都得不到处理;一个请求也可能因职责链没有被正确配置而得不到处理
责任链模式具体实例
请假审批问题 使用责任链模式简单实现前言所述的请假审批过程
代码实现 1.定义抽象的HoliadyHandler
类,并提供HandleHolidayRequest
接口:
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 class HolidayRequest{ private : string _type; int _days; public: HolidayRequest(string type , int days ) : _type(type ) , _days(days ) {}; public: string getType(void ) { return _type; } int getDays(void ) { return _days; } }; class HoliadyHandler{ protected: HoliadyHandler *_handler; public: HoliadyHandler() : _handler(NULL) {}; public: void setHandler(HoliadyHandler * handler ) { _handler = handler; } public: virtual void HandleHolidayRequest(HolidayRequest &request ) = 0 ; };
2.分别定义处理者HolidayRequest
的子类SectionChief
和Minister
及Director
:
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 class SectionChief : public HoliadyHandler{ private : string _name; public: SectionChief(string name ) : _name(name ) {}; public: void HandleHolidayRequest(HolidayRequest &request ) { if (request.getDays() <= 1 ) { cout << "Section chief " << _name << " approve your " << request.getDays() << " days for " << request.getType() << " request !" << endl; } else { if (NULL_POINTER(_handler ) ) { cout << "No holiday handler is assigned !" << endl; } else { _handler->HandleHolidayRequest(request ) ; } } } }; class Minister : public HoliadyHandler{ private : string _name; public: Minister(string name ) : _name(name ) {}; public: void HandleHolidayRequest(HolidayRequest &request ) { if (request.getDays() <= 3 ) { cout << "Minister " << _name << " approve your " << request.getDays() << " days for " << request.getType() << " request !" << endl; } else { if (NULL_POINTER(_handler ) ) { cout << "No holiday handler is assigned !" << endl; } else { _handler->HandleHolidayRequest(request ) ; } } } }; class Director : public HoliadyHandler{ private : string _name; public: Director(string name ) : _name(name ) {}; public: void HandleHolidayRequest(HolidayRequest &request ) { if (request.getDays() > 3 ) { cout << "Director " << _name << " approve your " << request.getDays() << " days for " << request.getType() << " request !" << endl; } else { if (NULL_POINTER(_handler ) ) { cout << "No holiday handler is assigned !" << endl; } else { _handler->HandleHolidayRequest(request ) ; } } } };
3.测试责任链模式:
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 void ResponseTest_Holiday() { HoliadyHandler *pD = new Director("john" ) ; HoliadyHandler *pM = new Minister("bob" ) ; HoliadyHandler *pS = new SectionChief("bill" ) ; pS->setHandler(pM ) ; pM->setHandler(pD ) ; pD->setHandler(NULL) ; HolidayRequest request1("dragon boat festival" , 1 ); HolidayRequest request2("mid-autumn festival" , 2 ); HolidayRequest request3("spring festival" , 3 ); HolidayRequest request4("spring festival" , 4 ); pS->HandleHolidayRequest(request1 ) ; pS->HandleHolidayRequest(request2 ) ; pS->HandleHolidayRequest(request3 ) ; pS->HandleHolidayRequest(request4 ) ; SAFE_RELASE_POINTER(pD ) ; SAFE_RELASE_POINTER(pM ) ; SAFE_RELASE_POINTER(pS ) ; }
4.运行结果:
Section chief bill approve your 1 days for dragon boat festival request !
Minister bob approve your 2 days for mid-autumn festival request !
Minister bob approve your 3 days for spring festival request !
Director john approve your 4 days for spring festival request !