当前位置:首页 > PHP教程 > php高级应用 > 列表

一文读懂php设计模式之责任链模式

发布: 来源: PHP粉丝网  添加日期:2022-07-22 14:32:49 浏览: 评论:0 

责任链模式属于行为型设计模式,将请求沿着处理者链进行发送, 收到请求后, 每个处理者均可对请求进行处理, 或将请求传递给链上的下个处理者,链上的每个处理者都有自己的处理职责,所以叫责任链模式。

场景

假如目前有一个系统,现在我们希望对系统的访问进行限制。首先是登录验证,该系统的所有请求都需要在登录状态下才能获取。

过了一段时间后,老板觉得应该加入防爬虫程序。老板的任务最大,你立即将防爬虫的功能加入到原本的校验代码中。目前就登录校验以及防爬虫校验,还不是很复杂。但又过了几天,老板又觉得应该加入限流的校验……。过了几天,老板……。

关于校验的代码块已经变的臃肿不堪,代码变得难以阅读、难以维护。这个时候,如果我们用责任链模式来重写校验的功能系统,那么就会像下面一样:

一文读懂php设计模式之责任链模式

通过责任链模式,多个处理者都有机会处理请求。将原本的模块分成多个处理者来处理,符合单一职责原则,代码的可读性也大大提高。另外,非常容易扩展,需要新的校验功能时,只要添加新的处理者即可,符合开闭原则。

责任链模式结构

下面我们来完成一个责任链模式结构的代码。每个处理者的功能非常简单,就是处理请求,然后设置下一个请求处理者。下面是示例代码:

  1. abstract class AHandler 
  2.  
  3.  
  4.     protected $nextHandler = null; 
  5.  
  6.       
  7.  
  8.     public function setNext (AHandler $handler
  9.  
  10.     { 
  11.  
  12.         $this->nextHandler = $handler
  13.  
  14.     } 
  15.  
  16.       
  17.  
  18.     abstract public function handler (); 
  19.  
  20.  
  21. class Handler1 extends AHandler 
  22.  
  23.  
  24.     public function handler() 
  25.  
  26.     { 
  27.  
  28.         $handled = false; 
  29.  
  30.           
  31.  
  32.         // 处理请求 
  33.  
  34.         echo 'Handler1接受到了请求' . PHP_EOL; 
  35.  
  36.           
  37.  
  38.         if (!$handled && $this->nextHandler) { 
  39.  
  40.             $this->nextHandler->handler(); 
  41.  
  42.         } 
  43.  
  44.     } 
  45.  
  46.  
  47. class Handler2 extends AHandler 
  48.  
  49.  
  50.     public function handler() 
  51.  
  52.     { 
  53.  
  54.         $handled = false; 
  55.  
  56.           
  57.  
  58.         // 处理请求 
  59.  
  60.         echo 'Handler2接受到了请求' . PHP_EOL; 
  61.  
  62.           
  63.  
  64.         if (!$handled && $this->nextHandler) { 
  65.  
  66.             $this->nextHandler->handler(); 
  67.  
  68.         } 
  69.  
  70.     } 
  71.  
  72.  
  73. class Handler3 extends AHandler 
  74.  
  75.  
  76.     public function handler() 
  77.  
  78.     { 
  79.  
  80.         $handled = false; 
  81.  
  82.           
  83.  
  84.         // 处理请求 
  85.  
  86.         echo 'Handler3接受到了请求' . PHP_EOL; 
  87.  
  88.           
  89.  
  90.         if (!$handled && $this->nextHandler) { 
  91.  
  92.             $this->nextHandler->handler(); 
  93.  
  94.         } 
  95.  
  96.     } 
  97.  

使用代码实例如下:

  1. $handler1 = new Handler1(); 
  2.  
  3. $handler2 = new Handler2(); 
  4.  
  5. $handler3 = new Handler3(); 
  6.  
  7. $handler1->setNext($handler2); 
  8.  
  9. $handler2->setNext($handler3); 
  10.  
  11. $handler1->handler(); 

上述代码虽然完成了责任链的结构,但还有一些问题,如果程序员对业务或责任链模式不太清楚的话,可能会忘记在handler方法里加入下面这段代码:

  1. if (!$handled && $this->nextHandler) { 
  2.  
  3.     $this->nextHandler->handler(); 
  4.  

那么就会造成责任链中断。另外,如果我们的处理者有10个或者更多,那么就要new出10个处理者,然后还要执行9次setNext。如果一不小心,写错了,就尴尬了。

现在,我们修改下上述的代码,修改后的代码如下:

  1. abstract class AHandler 
  2.  
  3.  
  4.     protected $nextHandler = null; 
  5.  
  6.       
  7.  
  8.     public function setNext (AHandler $handler
  9.  
  10.     { 
  11.  
  12.         $this->nextHandler = $handler
  13.  
  14.     } 
  15.  
  16.       
  17.  
  18.     // 使用了模板方法模式,防止程序员忘记写下段代码 
  19.  
  20.     public function handler () 
  21.  
  22.     { 
  23.  
  24.         if (!$this->doHandler() && $this->nextHandler) { 
  25.  
  26.             $this->nextHandler->handler(); 
  27.  
  28.         } 
  29.  
  30.     } 
  31.  
  32.       
  33.  
  34.     abstract public function doHandler (); 
  35.  
  36.  
  37.  
  38.  
  39. class Handler1 extends AHandler 
  40.  
  41.  
  42.     public function doHandler() 
  43.  
  44.     { 
  45.  
  46.         $handled = false; 
  47.  
  48.           
  49.  
  50.         // 处理请求 
  51.  
  52.         echo 'Handler1接受到了请求' . PHP_EOL; 
  53.  
  54.           
  55.  
  56.         return $handled
  57.  
  58.     } 
  59.  
  60.  
  61. class Handler2 extends AHandler 
  62.  
  63.  
  64.     public function doHandler() 
  65.  
  66.     { 
  67.  
  68.         $handled = false; 
  69.  
  70.           
  71.  
  72.         // 处理请求 
  73.  
  74.         echo 'Handler2接受到了请求' . PHP_EOL; 
  75.  
  76.           
  77.  
  78.         return $handled
  79.  
  80.     } 
  81.  
  82.  
  83.  
  84.  
  85. class Handler3 extends AHandler 
  86.  
  87.  
  88.     public function doHandler() 
  89.  
  90.     { 
  91.  
  92.         $handled = false; 
  93.  
  94.           
  95.  
  96.         // 处理请求 
  97.  
  98.         echo 'Handler3接受到了请求' . PHP_EOL; 
  99.  
  100.           
  101.  
  102.         return $handled
  103.  
  104.     } 
  105.  
  106.  
  107.  
  108.  
  109. class HandlerChain 
  110.  
  111.  
  112.     private $handlerChains = []; 
  113.  
  114.       
  115.  
  116.     public function __construct(array $handlerChains
  117.  
  118.     { 
  119.  
  120.         $this->handlerChains = $handlerChains
  121.  
  122.     } 
  123.  
  124.       
  125.  
  126.     public function addHandler (AHandler $handler
  127.  
  128.     { 
  129.  
  130.         $this->handlerChains[] = $handler
  131.  
  132.     } 
  133.  
  134.       
  135.  
  136.     public function handler () 
  137.  
  138.     { 
  139.  
  140.         $hdCnt = count($this->handlerChains); 
  141.  
  142.           
  143.  
  144.         for ($i = 0; $i < $hdCnt$i ++) { 
  145.  
  146.             if (isset($this->handlerChains[$i])  
  147.  
  148.                   && isset($this->handlerChains[$i+1])) { 
  149.  
  150.                 $this->handlerChains[$i]->setNext($this->handlerChains[$i+1]); 
  151.  
  152.             } 
  153.  
  154.         } 
  155.  
  156.           
  157.  
  158.         $this->handlerChains[0]->handler(); 
  159.  
  160.     } 
  161.  

然后,使用代码如下:

  1. $handler1 = new Handler1(); 
  2.  
  3. $handler2 = new Handler2(); 
  4.  
  5. $handler3 = new Handler3(); 
  6.  
  7. $handerChian = new HandlerChain([$handler1$handler2$handler3]); 
  8.  
  9. $handerChian->handler(); 

更简单的实现方法

其实有一种更加简单的实现责任链模式的方法,代码如下:

  1. abstract class AHandler 
  2.  
  3.  
  4.     abstract public function handler (); 
  5.  
  6.  
  7.  
  8.  
  9. class Handler1 extends AHandler 
  10.  
  11.  
  12.     public function handler() 
  13.  
  14.     { 
  15.  
  16.         $handled = false; 
  17.  
  18.         // 处理请求 
  19.  
  20.         echo 'Handler1接受到了请求' . PHP_EOL; 
  21.  
  22.         return $handled
  23.  
  24.     } 
  25.  
  26.  
  27.  
  28.  
  29. // Handler2、Handler3代码省略 
  30.  
  31.  
  32.  
  33.  
  34.  
  35. class HandlerChain 
  36.  
  37.  
  38.     private $handlerChains = []; 
  39.  
  40.       
  41.  
  42.     public function __construct(array $handlerChains
  43.  
  44.     { 
  45.  
  46.         $this->handlerChains = $handlerChains
  47.  
  48.     } 
  49.  
  50.       
  51.  
  52.     public function addHandler (AHandler $handler
  53.  
  54.     { 
  55.  
  56.         $this->handlerChains[] = $handler
  57.  
  58.     } 
  59.  
  60.       
  61.  
  62.     public function handler () 
  63.  
  64.     { 
  65.  
  66.         foreach ($this->handlerChains as $handler) { 
  67.  
  68.             if ($handler->handler()) { 
  69.  
  70.                 break
  71.  
  72.             } 
  73.  
  74.         } 
  75.  
  76.     } 
  77.  

总结:

通过责任链模式,多个处理者都有机会处理请求。将原本的模块分成多个处理者来处理,符合单一职责原则,代码的可读性也大大提高。另外,非常容易扩展,需要新的功能时,只要添加新的处理者即可。

一般设计模式的定义是,处理者如果不能够处理该请求,就将请求传递给后一个处理者。其实,他也有一个变体,就是每个处理者都会处理请求。

Tags: php设计模式 php责任链模式

分享到: