1.概述

你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决,不能解决就推卸给另外个一个部门(对象)。至于到底谁来解决这个问题呢?政府部门就是为了可以避免屁民的请求与官员之间耦合在一起,让多个(部门)对象都有可能接收请求,将这些(部门)对象连接成一条链,并且沿着这条链传递请求,直到有(部门)对象处理它为止。

2.问题

如果有多个对象都有可能接受请求,如何避免避免请求发送者与接收者耦合在一起呢?

3.解决方案

职责链模式(Chain of Responsibility)使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。(Avoid coupling the sender of a request to itsreceiver by giving morethan one objecta chance to handle the request.Chain the receiving objects andpassthe request along the chain until an object handles it. )

1)在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。
2)请求在这条链上传递,直到链上的某一个对象处理此请求为止。
3)发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。

4.适用性

在以下条件下使用Responsibility 链:

• 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。

• 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。

•可动态指定一组对象处理请求。

5.结构

一个典型的对象结构可能如下图所示:

6. 模式的组成

抽象处理者角色(Handler:Approver):定义一个处理请求的接口,和一个后继连接(可选)

具体处理者角色(ConcreteHandler:President):处理它所负责的请求,可以访问后继者,如果可以处理请求则处理,否则将该请求转给他的后继者。

客户类(Client):向一个链上的具体处理者ConcreteHandler对象提交请求。

7. 效果

Responsibility 链有下列优点和缺点( l i a b i l i t i e s ) :

职责链模式的优点:

1 ) 降低耦合度 :该模式使得一个对象无需知道是其他哪一个对象处理其请求。对象仅需知道该请求会被“正确”地处理。接收者和发送者都没有对方的明确的信息,且链中的对象不需知道链的结构。

2) 职责链可简化对象的相互连接 :    结果是,职责链可简化对象的相互连接。它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用。

3) 增强了给对象指派职责( R e s p o n s i b i l i t y )的灵活性 :当在对象中分派职责时,职责链给你更多的灵活性。你可以通过在运行时刻对该链进行动态的增加或修改来增加或改变处理一个请求的那些职责。你可以将这种机制与静态的特例化处理对象的继承机制结合起来使用。

4)增加新的请求处理类很方便

职责链模式的缺点:
1) • 不能保证请求一定被接收。既然一个请求没有明确的接收者,那么就不能保证它一定会被处理 —该请求可能一直到链的末端都得不到处理。一个请求也可能因该链没有被正确配置而得不到处理。
2) • 系统性能将受到一定影响,而且在进行代码调试时不太方便;可能会造成循环调用。
8. 纯与不纯的职责链模式
纯的职责链模式:一个具体处理者角色处理只能对请求作出两种行为中的一个:一个是自己处理(承担责任),另一个是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又将责任向下传的情况。请求在责任链中必须被处理,不能出现无果而终的结局。
反之就是不纯的职责链模式。  
在一个纯的职责链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的职责链模式里面,一个请求可以最终不被任何接收端对象所接收。

9.实现

我们先来看不纯的职责模式:

假如在公司里,

如果你的请假时间小于0.5天,那么只需要向leader打声招呼就OK了。
如果0.5<请假天数<=3天,需要先leader打声招呼,要不然leader不知你跑哪里,然后部门经理直接签字。
如果3<请假天数 天,需要先leader打声招呼,然后到部门经理签字,最好总经经理确认签字,

当你看到这情况后你心里是不是已经有了自己的想法了?写一系列的if语句来一条条的判断.但这样的写法虽然可以实现目前的需求,可如果当流程改了呢?我请假超过3天,告诉leader和总经理签字就可以,那你又得一步一步修改程序。如果if语句的条数发生变化的话我们还必须在代码中添加必要的if判断,这对于程序的维护来说是相当麻烦的.如果我们使用职责链模式的话就可以相当简单了.

这个例子就是个list。也是个不纯的职责链,因为每个对象可能处理一部分后,就需要传给下个对象来处理。

  1. <?php
  2. /**
  3. * 加入在公司里,如果你的请假时间小于0.5天,那么只需要向leader打声招呼就OK了。
  4.   如果0.5<请假天数<=3天,需要先leader打声招呼,要不然leader不知你跑哪里,然后部门经理直接签字。
  5.   如果3<请假天数 天,需要先leader打声招呼,然后到部门经理签字,最好总经经理确认签字,
  6.   这样就是个list。也是个不纯的职责链,因为每个对象可能处理一部分后,就需要传给下个对象来处理。
  7.   
  8. */
  9. /**
  10. * 纯职责链模式
  11. *
  12. * 为解除请求的发送者和接收者之间的耦合,而使用多个对象都用机会处理这个请求,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它
  13. * @author guisu
  14. *
  15. */
  16. /**
  17. * 抽象处理者角色(Handler:Approver):定义一个处理请求的接口,和一个后继连接(可选)
  18. *
  19. */
  20. abstract class Handler
  21. {
  22. protected $_handler = null;
  23. protected $_handlerName = null;
  24. public function setSuccessor($handler)
  25. {
  26. $this->_handler = $handler;
  27. }
  28. protected  function _success($request)
  29. {
  30. echo $request->getName(), '\' request was passed  <br/>';
  31. return true;
  32. }
  33. abstract function handleRequest($request);
  34. }
  35. /**
  36. * 具体处理者角色(ConcreteHandler:President):处理它所负责的请求,可以访问后继者,如果可以处理请求则处理,否则将该请求转给他的后继者。
  37. *
  38. */
  39. class ConcreteHandlerLeader extends Handler
  40. {
  41. function __construct($handlerName){
  42. $this->_handlerName = $handlerName;
  43. }
  44. public function handleRequest($request)
  45. {
  46. echo $this->_handlerName, ' was known <br/>';//已经跟leader招呼了
  47. if($request->getDay() < 0.5) {
  48. return $this->_success($request);
  49. }
  50. if ($this->_handler instanceof Handler) {
  51. return $this->_handler->handleRequest($request);
  52. }
  53. }
  54. }
  55. /**
  56. * Manager
  57. *
  58. */
  59. class ConcreteHandlerManager extends Handler
  60. {
  61. function __construct($handlerName){
  62. $this->_handlerName = $handlerName;
  63. }
  64. public function handleRequest($request)
  65. {
  66. echo $this->_handlerName, " was signed <br/>";//部门经理签字
  67. if( $request->getDay() > 0.5 && $request->getDay()<=3) {
  68. return $this->_success($request);
  69. }
  70. if ($this->_handler instanceof Handler) {
  71. return $this->_handler->handleRequest($request);
  72. }
  73. }
  74. }
  75. class ConcreteHandlerGeneralManager extends Handler
  76. {
  77. function __construct($handlerName){
  78. $this->_handlerName = $handlerName;
  79. }
  80. public function handleRequest($request)
  81. {
  82. echo $this->_handlerName, " was signed <br/>";//总经理签字
  83. if(3 < $request->getDay()){
  84. return $this->_success($request);
  85. }
  86. if ($this->_handler instanceof Handler) {
  87. return $this->_handler->handleRequest($request);
  88. }
  89. }
  90. }
  91. /**
  92. * 请假申请
  93. *
  94. */
  95. class   Request
  96. {
  97. private $_name;
  98. private $_day;
  99. private $_reason;
  100. function __construct($name= '', $day= 0, $reason = ''){
  101. $this->_name = $name;
  102. $this->_day = $day;
  103. $this->_reason = $reason;
  104. }
  105. public function setName($name){
  106. $this->_name = $name;
  107. }
  108. public function getName(){
  109. return  $this->_name;
  110. }
  111. public function setDay($day){
  112. $this->_day = $day;
  113. }
  114. public function getDay(){
  115. return  $this->_day ;
  116. }
  117. public function setReason($reason ){
  118. $this->_reason = $reason;
  119. }
  120. public function getReason( ){
  121. return  $this->_reason;
  122. }
  123. }
  124. class client{
  125. /**
  126. *流程1:leader-> manager ->generalManager
  127. *
  128. */
  129. static function main(){
  130. $leader = new ConcreteHandlerLeader('$leader');
  131. $manager = new ConcreteHandlerManager('$manager');
  132. $generalManager = new ConcreteHandlerGeneralManager('$generalManager');
  133. //请求实例
  134. $request = new Request('guisu',4,'休息' );
  135. $leader->setSuccessor($manager);
  136. $manager->setSuccessor($generalManager);
  137. $result =  $leader->handleRequest($request);
  138. }
  139. /**
  140. * 流程2 :
  141. * leader ->generalManager
  142. */
  143. static function main2(){
  144. //签字列表
  145. $leader = new ConcreteHandlerLeader('$leader');
  146. $manager = new ConcreteHandlerManager('$manager');
  147. $generalManager = new ConcreteHandlerGeneralManager('$generalManager');
  148. //请求实例
  149. $request = new Request('guisu',3,'休息' );
  150. $leader->setSuccessor($generalManager);
  151. $result = $leader->handleRequest($request);
  152. }
  153. /**
  154. * 流程3 :如果leader不在,那么完全可以写这样的代码
  155. * manager ->generalManager
  156. */
  157. static function main3(){
  158. //签字列表
  159. $leader = new ConcreteHandlerLeader('$leader');
  160. $manager = new ConcreteHandlerManager('$manager');
  161. $generalManager = new ConcreteHandlerGeneralManager('$generalManager');
  162. //请求实例
  163. $request = new Request('guisu',0.1,'休息' );
  164. $leader->setSuccessor($manager);
  165. $manager->setSuccessor($generalManager);
  166. $result = $manager->handleRequest($request);
  167. }
  168. }
  169. client::main3();

对于怎么维护职责的链子,《设计模式》仅仅说自己去实现,可以使用list或者map的形式。

我们吧把职责链模式应用到面向过程编程,而不是对象。例如:

  1. 个税起征点3500元
  2. 级数   全月应纳税所得额            税率(%)
  3. 1    不超过1500元的                3
  4. 2    超过1500元至4500元的部分      10
  5. 3    超过4500元至9000元的部分      20
  6. 4    超过9000元至35000元的部分     25
  7. 5    超过35000元至55000元的部分    30
  8. 6    超过55000元至80000元的部分    35
  9. 7    超过80000元的部分              45

我们可以不必使用那么多的if和elseif语句判断。我们只要配置$taxs数组就可以了,而不用修改程序。

  1. <?php
  2. /**
  3. * 个税起征点3500元
  4. 级数   全月应纳税所得额            税率(%)
  5.    1    不超过1500元的                3
  6.    2    超过1500元至4500元的部分      10
  7.    3    超过4500元至9000元的部分      20
  8.    4    超过9000元至35000元的部分     25
  9.    5    超过35000元至55000元的部分    30
  10.    6    超过55000元至80000元的部分    35
  11.    7    超过80000元的部分             45
  12. */
  13. /**
  14. * 这个例子还没有扣除社保公积金等
  15. */
  16. //收入
  17. $income = 84000;
  18. //税率
  19. $taxs[1] = array(1500, 0.03);
  20. $taxs[2] = array(4500, 0.1);
  21. $taxs[3] = array(9000, 0.2);
  22. $taxs[4] = array(35000, 0.25);
  23. $taxs[5] = array(55000, 0.30);
  24. $taxs[6] = array(80000, 0.35);
  25. $taxs[7] = array(1000000000, 0.45);
  26. /**
  27. * 计算税率
  28. *
  29. * @param int $income
  30. * @return int
  31. */
  32. function compTax($income){
  33. global $taxs;
  34. //个税起点
  35. $taxStart  = 3500;
  36. $incomeTax = $income > $taxStart ?($income - $taxStart) : 0;
  37. $flag = false;
  38. foreach ($taxs as $values) {
  39. if ($incomeTax < $values[0]  ) {
  40. $compTax = $incomeTax * $values[1];
  41. break;
  42. }else{
  43. continue;
  44. }
  45. }
  46. return $compTax;
  47. }
  48. echo compTax($income);
  49. echo '-------------------<br/>';

如果判断的条件很多,也就是数组$taxs很庞大。那么我们可以使用折半查找的方式:

  1. <?php
  2. /**
  3. * 个税起征点3500元
  4. 级数   全月应纳税所得额            税率(%)
  5.    1    不超过1500元的                3
  6.    2    超过1500元至4500元的部分      10
  7.    3    超过4500元至9000元的部分      20
  8.    4    超过9000元至35000元的部分     25
  9.    5    超过35000元至55000元的部分    30
  10.    6    超过55000元至80000元的部分    35
  11.    7    超过80000元的部分             45
  12. */
  13. /**
  14. * 这个例子还没有扣除社保公积金等
  15. */
  16. //收入
  17. $income = 84000;
  18. //税率
  19. $taxs[1] = array(1500, 0.03);
  20. $taxs[2] = array(4500, 0.1);
  21. $taxs[3] = array(9000, 0.2);
  22. $taxs[4] = array(35000, 0.25);
  23. $taxs[5] = array(55000, 0.30);
  24. $taxs[6] = array(80000, 0.35);
  25. $taxs[7] = array(1000000000, 0.45);
  26. /**
  27. * 优化计算税率:使用折半查找法,有效缩短时间复杂度
  28. */
  29. /**
  30. * 优化计算税率:折半查找法
  31. *
  32. * @param int $income
  33. * @return int
  34. */
  35. function optimizeCompTax($income){
  36. //个税起点
  37. global $taxs;
  38. $taxStart  = 3500;
  39. $incomeTax = $income > $taxStart ?($income - $taxStart) : 0;
  40. $key = bSearch($taxs, $incomeTax, 1);
  41. return $incomeTax * $taxs[$key][1];
  42. }
  43. /**
  44. *
  45. * 折半查找法
  46. * @param unknown_type $taxs
  47. * @param unknown_type $incomeTax
  48. * @return unknown
  49. */
  50. function bSearch($taxs, $incomeTax, $start = 0){
  51. $incomeTax = intval($incomeTax);
  52. ksort($taxs);
  53. foreach ($taxs as $key => $values) {
  54. $low = $key;
  55. break;
  56. }
  57. if ($incomeTax <=0 ) {
  58. return $low;
  59. }
  60. $high = count($taxs) + $low -1;
  61. while  ( $low < $high){
  62. $mid = intval(($low + $high)/2) ;
  63. if ( $incomeTax < $taxs[$mid][0] ) {//后半区找
  64. $high = $mid;
  65. } else { //前半区找
  66. $low = $mid ;
  67. }
  68. /**
  69. * 由于这个不是完全折半查找
  70. * 只有两个元素的时候,需要判断
  71. */
  72. if (($high - $low) ==1) {
  73. if ( $incomeTax > $taxs[$low][0] ) {
  74. $key = $high;
  75. } else{
  76. $key = $low;
  77. }
  78. break;
  79. }
  80. }
  81. return $key;
  82. }
  83. echo optimizeCompTax($income);

10.与其他相关模式

职责链常与Composite组合模式一起使用。这种情况下,一个构件的父构件可作为它的后继

11.总结

      

职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。

      职责链模式的主要优点在于可以降低系统的耦合度,简化对象的相互连接,同时增强给对象指派职责的灵活性,增加新的请求处理类也很方便;其主要缺点在于不能保证请求一定被接收,且对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,而且在进行代码调试时不太方便。

职责链模式(Chain of Responsibility)(对象行为型)的更多相关文章

  1. 责任链模式 职责链模式 Chain of Responsibility Pattern 行为型 设计模式(十七)

    责任链模式(Chain of Responsibility Pattern) 职责链模式 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系 将这些对象连接成一条链,并沿着这 ...

  2. 设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型)

     设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决,不能解决就 ...

  3. 设计模式 ( 十二 ) 职责链模式(Chain of Responsibility)(对象行为)

     设计模式(十二)职责链模式(Chain of Responsibility)(对象行为型) 1.概述 你去政府部门求人办事过吗?有时候你会遇到过官员踢球推责,你的问题在我这里能解决就解决.不能解决就 ...

  4. atitit.设计模式(1)--—职责链模式(chain of responsibility)最佳实践O7 日期转换

    atitit.设计模式(1)---职责链模式(chain of responsibility)最佳实践O7 日期转换 1. 需求:::日期转换 1 2. 可以选择的模式: 表格模式,责任链模式 1 3 ...

  5. 设计模式之职责链模式(Chain of Responsibility)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于怎样创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...

  6. 行为型设计模式之职责链模式(Chain of Responsibility)

    结构 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 适用性 有多个的对象可以处理一个请求,哪个 ...

  7. 职责链模式(chain of responsibility)

    一. 写在前面的 这么多的设计模式,我觉得职责链是我第一次看上去最简单,可是回想起来却又最复杂的一个模式. 因此,这个文章我酝酿了很久,一直也没有胆量发出来,例子也是改了又改,可是仍然觉得不够合理.所 ...

  8. 职责链模式(chain of responsibility Pattern)

    职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止. •Handler: 抽象处理者:定义出一个 ...

  9. C#设计模式——职责链模式(Chain Of Responsibility Pattern)

    一.概述 在软件开发中,某一个对象的请求可能会被多个对象处理,但每次最多只有一个对象处理该请求,对这类问题如果显示指定请求的处理对象,那么势必会造成请求与处理的紧耦合,为了将请求与处理解耦,我们可以使 ...

随机推荐

  1. [转]Intercepting the App Store's Traffic on iOS

    Source:https://nabla-c0d3.github.io/blog/2013/08/20/intercepting-the-app-stores-traffic-on-ios/ TL;D ...

  2. Orchard是一个了不起CMS(内容管理系统)

    在这个系列中,我们将共同经历从头开始构建一个Orchard模块的过程! 虽然Orchard是一个了不起CMS(内容管理系统),有着强大的功能和令人振奋的架构,可以无限的扩展,但它可能需要花费一定时间, ...

  3. 为什么选择MongoDB?

    为什么选择MongoDB? 阅读目录 开始 为啥用MongoDB? 原来的架构 新需求 如何解决? 新思路 选型条件 一些候选者 最初的选择 代价 新的候选者 重新选择 胆子大一点 胆子再大一点 胆子 ...

  4. .NET 微信开放平台接口(接收短信、发送短信)

    .NET 微信开放平台接口(接收短信.发送短信) 前两天做个项目用到了微信api功能.项目完成后经过整理封装如下微信操作类. 以下功能的实现需要开发者已有微信的公众平台账号,并且开发模式已开启.接口配 ...

  5. No CurrentSessionContext configured 异常解决

    Exception in thread "main" org.hibernate.HibernateException: No CurrentSessionContext conf ...

  6. 二.redis 数据类型

    本文介绍下redis支持的各种数据类型包括string,list ,set ,sorted set 和hash 1. keysredis本质上一个key-value db,所以我们首先来看看他的key ...

  7. Entity Framework实体模型 入门视频教程

    Entity Framework实体模型 入门视频教程 恢复内容开始--- 第一步 创建一个 控制台应用程序 第二步 创建一个ADO.NET 数据实体模型 DbModel.edmx 需要跟数据库进行连 ...

  8. DotNetBar v11.4.0.6 Fully Cracked

    更新信息: http://www.devcomponents.com/customeronly/releasenotes.asp?p=dnbwf&v=11.4.0.6 如果遇到破解问题可以与我 ...

  9. 40w会议投票系统优化方案

    40w会议投票系统优化方案 最近2天谈了一个项目,根据提出的需求是,该系统本来是属于一个大系统的分割出来的一个很小的系统,但是由于是并发关系会耗费资源很大,所以分割出来.据了解,系统采用的mysql+ ...

  10. yowsup ( an application to use whatsapp) hack

    yowsup, in python https://github.com/tgalal/yowsup try this: http://hacktracking.blogspot.com.ar/201 ...