共计 3570 个字符,预计需要花费 9 分钟才能阅读完成。
责任链模式,属于对象行为型的设计模式。
Gof 类图及解释
GoF 定义:使多个对象都有机会解决申请,从而防止申请的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该申请,直到有一个对象解决它为止。
GoF 类图
代码实现
abstract class Handler
{
protected $successor;
public function setSuccessor($successor)
{$this->successor = $successor;}
abstract public function HandleRequst($request);
}
定义形象责任链类,应用 $successor 保留后继链条。
class ConcreteHandler1 extends Handler
{public function HandleRequst($request)
{if (is_numeric($request)) {return '申请参数是数字:' . $request;} else {return $this->successor->HandleRequst($request);
}
}
}
class ConcreteHandler2 extends Handler
{public function HandleRequst($request)
{if (is_string($request)) {return '申请参数是字符串:' . $request;} else {return $this->successor->HandleRequst($request);
}
}
}
class ConcreteHandler3 extends Handler
{public function HandleRequst($request)
{return '我也不晓得申请参数是啥了,你猜猜?' . gettype($request);
}
}
三个责任链条的具体实现,次要性能是判断传入的数据类型,如果是数字由第一个类解决,如果是字符串,则第二个类解决。如果是其余类型,第三个类对立解决。
$handle1 = new ConcreteHandler1();
$handle2 = new ConcreteHandler2();
$handle3 = new ConcreteHandler3();
$handle1->setSuccessor($handle2);
$handle2->setSuccessor($handle3);
$requests = [22, 'aaa', 55, 'cc', [1, 2, 3], null, new stdClass];
foreach ($requests as $request) {echo $handle1->HandleRequst($request) . PHP_EOL;
}
客户端的调用,顺次实例化三个责任链实例,并指定链条成员。创立申请参数,之后通过责任链来进行后果判断。
- 责任链非常适合的一种场景,就是对申请参数进行逐层过滤,就像咱们工作时应用钉钉之类的办公软件。当须要提加班或者休假申请时,那一层层的审批流程就是对这个模式最完满的解释
- 咱们能够拦挡申请,间接返回,也能够对申请内容进行欠缺批改交给下一个类来进行解决,但至多有一个类是要返回后果的。
- 申请不肯定都会被解决,也有可能齐全不解决就返回或者传递给下一个解决类来进行解决
咱们始终在说手机制作这个行业,之前咱们始终是交给代工厂来进行手机的组装生产,这回,咱们本人建设了一条流水线。而这个流水线,就十分像责任链模式,怎么说呢,从一台手机的拆卸说起。有操作员将手机主板(初始申请)放到流水线上,而后工人开始增加内存、CPU、摄像头(各种责任链条类进行解决),期间也会通过测试和调整以达到最佳出厂性能。最初拼装成一台残缺的手机交到客户的手中,这种工作流是不是和责任链十分类似呢!!
残缺代码:https://github.com/zhangyue0503/designpatterns-php/blob/master/11.chain-of-responsiblity/source/chain.php
实例
仍然还是短信性能,但这次咱们要实现的是一个短信内容过滤的子性能。大家都晓得,咱们对广告有着严格的规定,许多词都在广告法中被标记为禁止应用的词汇,更有些重大的词汇可能会引来不必要的麻烦。这时候,咱们就须要一套过滤机制来进行词汇的过滤。针对不同类型的词汇,咱们能够通过责任链来进行过滤,比方重大守法的词汇当然是这条信息都不能通过。一些比较严重但能够绕过的词,咱们能够进行替换或者加星解决,这样,客户端不须要一大堆的 if..else.. 来进行逻辑判断,应用责任链让他们一步步的进行审批就好啦!!
短信发送类图
残缺源码:https://github.com/zhangyue0503/designpatterns-php/blob/master/11.chain-of-responsiblity/source/chain-filter-message.php
// 词汇过滤链条
abstract class FilterChain
{
protected $next;
public function setNext($next)
{$this->next = $next;}
abstract public function filter($message);
}
// 严禁词汇
class FilterStrict extends FilterChain
{public function filter($message)
{foreach (['枪 X', '弹 X', '毒 X'] as $v) {if (strpos($message, $v) !== false) {throw new \Exception('该信息蕴含敏感词汇!');
}
}
if ($this->next) {return $this->next->filter($message);
} else {return $message;}
}
}
// 正告词汇
class FilterWarning extends FilterChain
{public function filter($message)
{$message = str_replace(['打架', '丰胸', '偷税'], '*', $message);
if ($this->next) {return $this->next->filter($message);
} else {return $message;}
}
}
// 手机号加星
class FilterMobile extends FilterChain
{public function filter($message)
{$message = preg_replace("/(1[3|5|7|8]\d)\d{4}(\d{4})/i", "$1****$2", $message);
if ($this->next) {return $this->next->filter($message);
} else {return $message;}
}
}
$f1 = new FilterStrict();
$f2 = new FilterWarning();
$f3 = new FilterMobile();
$f1->setNext($f2);
$f2->setNext($f3);
$m1 = "当初开始测试链条 1:语句中不蕴含敏感词,须要替换掉打架这种词,而后给手机号加上星:13333333333,这样的数据才能够对外展现哦";
echo $f1->filter($m1);
echo PHP_EOL;
$m2 = "当初开始测试链条 2:这条语句走不到前面,因为蕴含了毒 X,间接就报错了!!!语句中不蕴含敏感词,须要替换掉打架这种词,而后给手机号加上星:13333333333,这样的数据才能够对外展现哦";
echo $f1->filter($m2);
echo PHP_EOL;
阐明
- 在这个例子中,咱们对音讯内容进行了各种解决。当有新的需要产生时,咱们只须要退出新的过滤类,而后调整客户端的执行程序即可
- 应用了 next 来标识下一步的操作,应用过 Laravel 的同学肯定马上联想到了中间件。当然,用过 Node 开发服务器的同学更是不会生疏,早就对这个设计模式一目了然了。
- 责任链的使用真的十分宽泛,在各种工作流软件及中间件组件中都能够看到,同时配合 Linux 下的管道思维,能够把这个模式的劣势施展到极致
- Laravel 的中间件,有趣味的敌人翻翻源码,典型的责任链模式的利用哦
下期看点
责任链貌似真的是十分高大上的一个设计模式,真的在目前很多的框架或零碎中都有成熟的利用,如果不理解这个模式,可能在浏览或者了解某些框架零碎常识时就会茫然无措。下回,咱们来看看另一个耳熟能详的模式,它叫做 代理模式。
各自媒体平台均可搜寻【硬核项目经理】