本文同步更新於blog
情境:公司开发了一个新产品,客户端有许多不同的请求
<?php
namespace App\ChainOfResponsibilityPattern\Software;
class Request
{
/**
* @var string
*/
protected $type;
/**
* @var string
*/
protected $content;
/**
* @param string $type
* @param string $content
*/
public function __construct(string $type, string $content)
{
$this->type = $type;
$this->content = $content;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* @return string
*/
public function getContent()
{
return $this->content;
}
}
<?php
namespace App\ChainOfResponsibilityPattern\Software;
use Tests\Unit\ChainOfResponsibilityPattern\Software\Request;
class Program
{
/**
* @param Request $request
* @return string
*/
public function handle(Request $request)
{
$type = $request->getType();
$content = $request->getContent();
switch ($type) {
case 'bug':
// $request = new Request('bug', 'no connection');
return "Support已开始处理[$type:$content]的问题。";
break;
case 'feature':
// $request = new Request('feature', 'add filter');
return "PM已开始处理[$type:$content]的问题。";
break;
default:
// $request = new Request('cooperative business', 'become Google partner');
return "Boss已开始处理[$type:$content]的问题。";
break;
}
}
}
根据请求类型的不同,我们会交由不同的角色来处理问题。
但这些请求,可以透过区分请求类别的方式,
统一先交由Support处理,若Support无法处理,再转给下个负责人。
以这样的想法,让我们用职责链模式改造它。
<?php
namespace App\ChainOfResponsibilityPattern\Software\Abstracts;
use App\ChainOfResponsibilityPattern\Software\Request;
abstract class Handler
{
/**
* @var string
*/
protected $role;
/**
* @var array
*/
protected $canHandleType = [];
/**
* @var string
*/
protected $requestType;
/**
* @var string
*/
protected $requestContent;
/**
* @var Handler
*/
protected $nextHandler;
/**
* @param Request $request
* @return string
*/
public function handle(Request $request): string
{
$this->requestType = $request->getType();
$this->requestContent = $request->getContent();
if ($this->canHandle()) {
$role = $this->role;
$result = "$role can solve [$this->requestType:$this->requestContent] issue.";
return $result;
}
return $this->nextHandler->handle($request);
}
/**
* @param Handler $handler
*/
public function setNextHandler(Handler $handler)
{
$this->nextHandler = $handler;
}
/**
* @return boolean
*/
protected function canHandle()
{
return in_array($this->requestType, $this->canHandleType);
}
}
由canHandle()方法来知道,该处理器能不能处理。
由setNextHandler()方法,来决定下一个处理器。
<?php
namespace App\ChainOfResponsibilityPattern\Software;
use App\ChainOfResponsibilityPattern\Software\Abstracts\Handler;
class Support extends Handler
{
/**
* @var string
*/
protected $role = 'Support';
/**
* @var array
*/
protected $canHandleType = ['bug'];
}
<?php
namespace App\ChainOfResponsibilityPattern\Software;
use App\ChainOfResponsibilityPattern\Software\Abstracts\Handler;
class ProjectManager extends Handler
{
/**
* @var string
*/
protected $role = 'PM';
/**
* @var array
*/
protected $canHandleType = ['bug', 'feature'];
}
<?php
namespace App\ChainOfResponsibilityPattern\Software;
use App\ChainOfResponsibilityPattern\Software\Abstracts\Handler;
class Boss extends Handler
{
/**
* @var string
*/
protected $role = 'Boss';
/**
* @return boolean
*/
protected function canHandle()
{
return true;
}
}
<?php
namespace App\ChainOfResponsibilityPattern\Software;
use App\ChainOfResponsibilityPattern\Software\Request;
use App\ChainOfResponsibilityPattern\Software\Support;
class Program
{
public function handle(Request $request)
{
$support = new Support();
$projectManager = new ProjectManager();
$boss = new Boss();
$support->setNextHandler($projectManager);
$projectManager->setNextHandler($boss);
return $support->handle($request);
}
}
这边可以留意,若有未定义类型的请求,最终都会交由Boss处理器来捕捉。
[单一职责原则]
我们把处理器与处理器的顺序视作两种不同的职责。
[开放封闭原则]
无论是新增/修改处理器的逻辑,或者修改处理器的顺序,
皆不会改动到所有程序码。
[依赖反转原则]
抽象的处理器类别依赖於自身(组合模式)。
实体的处理器类别则实现它。
最後附上类别图:
(注:若不熟悉 UML 类别图,可参考UML类别图说明。)
ʕ •ᴥ•ʔ:一个很生活化的设计模式。
<<: 资讯安全治理(Information Security Governance)
>>: iOS App开发 OC 第一天, @interface设计思维
之前都是使用RESTful API开发 换工作面试几轮之後发现有蛮多家公司都在使用gRPC 就多学一...
今日我们要介绍一下Kibana内的警报功能,在Elastic Stack 内有提供Kibana Al...
在前面,我们有讲解过 C# 的文本处理,这篇文章是对前面的内容的一个补充。 前面我们有讲解过,写入文...
场景与需求 APP跟网页一样,要被下载,最容易的办法就是要取得流量大的关键字的上位排名,也就是要做S...
selector 选取 JQ 的 DOM 存取方式是透过 selector 来达到索引目标,会先转换...