0

0

PHP 设计模式系列 -- 责任链模式(Chain Of Responsibilities)

php中文网

php中文网

发布时间:2016-06-20 12:41:45

|

1112人浏览过

|

来源于php中文网

原创

1、模式定义

责任链模式将处理请求的对象连成一条链,沿着这条链传递该请求,直到有一个对象处理请求为止,这使得多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。

责任链模式在现实中使用的很多,常见的就是 OA 系统中的工作流。

2、UML 类图

塔猫ChatPPT
塔猫ChatPPT

塔猫官网提供AI一键生成 PPT的智能工具,帮助您快速制作出专业的PPT。塔猫ChatPPT让您的PPT制作更加简单高效。

下载

立即学习PHP免费学习笔记(深入)”;

3、示例代码

Request.php

<?phpnamespace DesignPatterns\Behavioral\ChainOfResponsibilities;/** * 经过责任链的Request类 * * 关于请求: 有时候,不需要一个请求对象,只需一个整型数据或者一个数组即可。 * 但是作为一个完整示例,这里我们生成了一个请求类。 * 在实际项目中,也推荐使用请求类,即是是一个标准类\stdClass, * 因为这样的话代码更具扩展性,因为责任链的处理器并不了解外部世界, * 如果某天你想要添加其它复杂处理时不使用请求类会很麻烦 */class Request{    // getter and setter but I don't want to generate too much noise in handlers}

Handler.php

<?phpnamespace DesignPatterns\Behavioral\ChainOfResponsibilities;/** * 责任链的通用处理器类Handler(通常是一个接口或抽象类) * * Yes you could have a lighter CoR with a simpler handler but if you want your CoR * to be extendable and decoupled, it's a better idea to do things like that in real * situations. Usually, a CoR is meant to be changed everytime and evolves, that's * why we slice the workflow in little bits of code. */abstract class Handler{    /**     * @var Handler     */    private $successor = null;    /**     * 追加处理类到责任链     *     * A prepend method could be done with the same spirit     *     * You could also send the successor in the constructor but in PHP that is a     * bad idea because you have to remove the type-hint of the parameter because     * the last handler has a null successor.     *     * And if you override the constructor, that Handler can no longer have a     * successor. One solution is to provide a NullObject (see pattern).     * It is more preferable to keep the constructor "free" to inject services     * you need with the DiC of symfony2 for example.     *     * @param Handler $handler     */    final public function append(Handler $handler)    {        if (is_null($this->successor)) {            $this->successor = $handler;        } else {            $this->successor->append($handler);        }    }    /**     * 处理请求     *     * This approach by using a template method pattern ensures you that     * each subclass will not forget to call the successor. Besides, the returned     * boolean value indicates you if the request have been processed or not.     *     * @param Request $req     *     * @return bool     */    final public function handle(Request $req)    {        $req->forDebugOnly = get_called_class();        $processed = $this->processing($req);        if (!$processed) {            // the request has not been processed by this handler => see the next            if (!is_null($this->successor)) {                $processed = $this->successor->handle($req);            }        }        return $processed;    }    /**     * 每个处理器具体实现类都要实现这个方法对请求进行处理     *     * @param Request $req     *     * @return bool true if the request has been processed     */    abstract protected function processing(Request $req);}

Responsible/SlowStorage.php

<?phpnamespace DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible;use DesignPatterns\Behavioral\ChainOfResponsibilities\Handler;use DesignPatterns\Behavioral\ChainOfResponsibilities\Request;/** * This is mostly the same code as FastStorage but in fact, it may greatly differs * * One important fact about CoR: each item in the chain MUST NOT assume its position * in the chain. A CoR is not responsible if the request is not handled UNLESS * you make an "ExceptionHandler" which throws exception if the request goes there. * * To be really extendable, each handler doesn't know if there is something after it. * */class SlowStorage extends Handler{    /**     * @var array     */    protected $data = array();    /**     * @param array $data     */    public function __construct($data = array())    {        $this->data = $data;    }    protected function processing(Request $req)    {        if ('get' === $req->verb) {            if (array_key_exists($req->key, $this->data)) {                $req->response = $this->data[$req->key];                return true;            }        }        return false;    }}

Responsible/FastStorage.php

<?phpnamespace DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible;use DesignPatterns\Behavioral\ChainOfResponsibilities\Handler;use DesignPatterns\Behavioral\ChainOfResponsibilities\Request;/** * Class FastStorage */class FastStorage extends Handler{    /**     * @var array     */    protected $data = array();    /**     * @param array $data     */    public function __construct($data = array())    {        $this->data = $data;    }    protected function processing(Request $req)    {        if ('get' === $req->verb) {            if (array_key_exists($req->key, $this->data)) {                // the handler IS responsible and then processes the request                $req->response = $this->data[$req->key];                // instead of returning true, I could return the value but it proves                // to be a bad idea. What if the value IS "false" ?                return true;            }        }        return false;    }}

4、测试代码

Tests/ChainTest.php

<?phpnamespace DesignPatterns\Behavioral\ChainOfResponsibilities\Tests;use DesignPatterns\Behavioral\ChainOfResponsibilities\Request;use DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\FastStorage;use DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\SlowStorage;use DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible;/** * ChainTest tests the CoR */class ChainTest extends \PHPUnit_Framework_TestCase{    /**     * @var FastStorage     */    protected $chain;    protected function setUp()    {        $this->chain = new FastStorage(array('bar' => 'baz'));        $this->chain->append(new SlowStorage(array('bar' => 'baz', 'foo' => 'bar')));    }    public function makeRequest()    {        $request = new Request();        $request->verb = 'get';        return array(            array($request)        );    }    /**     * @dataProvider makeRequest     */    public function testFastStorage($request)    {        $request->key = 'bar';        $ret = $this->chain->handle($request);        $this->assertTrue($ret);        $this->assertObjectHasAttribute('response', $request);        $this->assertEquals('baz', $request->response);        // despite both handle owns the 'bar' key, the FastStorage is responding first        $className = 'DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\FastStorage';        $this->assertEquals($className, $request->forDebugOnly);    }    /**     * @dataProvider makeRequest     */    public function testSlowStorage($request)    {        $request->key = 'foo';        $ret = $this->chain->handle($request);        $this->assertTrue($ret);        $this->assertObjectHasAttribute('response', $request);        $this->assertEquals('bar', $request->response);        // FastStorage has no 'foo' key, the SlowStorage is responding        $className = 'DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\SlowStorage';        $this->assertEquals($className, $request->forDebugOnly);    }    /**     * @dataProvider makeRequest     */    public function testFailure($request)    {        $request->key = 'kurukuku';        $ret = $this->chain->handle($request);        $this->assertFalse($ret);        // the last responsible :        $className = 'DesignPatterns\Behavioral\ChainOfResponsibilities\Responsible\SlowStorage';        $this->assertEquals($className, $request->forDebugOnly);    }}

5、总结

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

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

705

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

233

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

117

2026.02.13

TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

22

2026.02.13

Redis高可用架构与分布式缓存实战
Redis高可用架构与分布式缓存实战

本专题围绕 Redis 在高并发系统中的应用展开,系统讲解主从复制、哨兵机制、Cluster 集群模式及数据分片原理。内容涵盖缓存穿透与雪崩解决方案、分布式锁实现、热点数据优化及持久化策略。通过真实业务场景演示,帮助开发者构建高可用、可扩展的分布式缓存系统。

61

2026.02.13

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

30

2026.02.12

雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法
雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法

本专题系统整理雨课堂网页版官方入口及在线登录方式,涵盖账号登录流程、官方直连入口及平台访问方法说明,帮助师生用户快速进入雨课堂在线教学平台,实现便捷、高效的课程学习与教学管理体验。

15

2026.02.12

豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法
豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法

本专题汇总豆包AI官方网页版入口及在线使用方式,涵盖智能写作工具、图片生成体验入口和官网登录方法,帮助用户快速直达豆包AI平台,高效完成文本创作与AI生图任务,实现便捷智能创作体验。

669

2026.02.12

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

58

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号