`
xieye
  • 浏览: 806503 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

php设计模式(3)-- 责任链(职责链) 模式

    博客分类:
  • PHP
阅读更多
我的设计模式系列文章
php设计模式(1)-- 观察者模式 -- spl标准写法
php设计模式(2)-- 观察者模式 -- 用trait来改进的写法
php设计模式(3)-- 责任链(职责链)模式
php设计模式(4)-- 装饰器模式



这次讨论责任链。

分析

实际上,责任链很想象软件开发中的中间件,请求只有一个,但是会有很多处理对象,每个处理对象都包含下一个对象,每个处理对象都有权处理。

主要角色,处理类,以及其共同接口
次要角色,请求对象。

网上的代码很多,主要是一个员工请假的需求,太无聊了。下面我构造一个需求,假设请求是用户想要修改他自己的密码,于是请求对象包含请求url,用户名,原密码,新密码。
还有一个需求,用户检查他的粉丝,不需要登录校验。
在处理过程中,我会记录所有请求的日志,这里使用一个处理类。
在处理过程中,有些请求需要校验用户密码,有些不需要,这是登录验证请求。
在处理过程中,如果请求url错误,会报告错误。

所以总共是日志处理器,登录校验处理器,密码修改处理器,查询粉丝处理器。
经验体会,该模式可以有返回值,也可以没有返回值。随意。
经验2:构造责任处理器链,是在客户端代码中,请注意这一点。

代码实现

<?php

/**
 * 责任链的处理器 共同抽象接口
 */
abstract class Handler 
{
    protected $successor;
    
    // 处理请求对象
    abstract  public function handleRequest($request);
    
    // 设置下个处理器。
    public function setSuccessor(Handler $next_handler){
        $this->successor = $next_handler;
    }
}

/**
 * 这是请求对象
 */
class Request
{
    public $url;
    public $username;
    public $password;
    public $request_parameter;
    public function __construct($url,$username, $password, array $request_parameter){
        $this->url=$url;
        $this->username=$username;
        $this->password=$password;
        $this->request_parameter=$request_parameter;
    }
}

/**
 * 日志处理器
 */
class Log extends Handler
{
    public function  handleRequest($request)
    {
        echo "url:{$request->url}; request_parameter:" . json_encode($request->request_parameter) 
            . PHP_EOL;
        if ($this->successor) { // 直接把请求传递下去
            return $this->successor->handleRequest($request);
        }
        return ['code'=>0];
    }
}

/**
 * 身份检验处理器,应该使用数据库,这里用数组代替
 */
class Verification extends Handler
{
    protected $all_user;
    protected $all_url;
    
    public function __construct(){
        $this->all_users = [
            'name1' =>'123',
            'name2' => '456',
        ];
        $this->check_urls = [
            'change_password',
        ];
    }
    
    private function continue_request($request){
        if ($this->successor) { // 直接把请求传递下去
            return $this->successor->handleRequest($request);
        }
    }
    
    public function  handleRequest($request)
    {
        if (in_array( $request->url, $this->check_urls )) {
            if ( array_key_exists($request->username, $this->all_users ) &&
                 $request->password == $this->all_users[$request->username]  ) {
                return $this->continue_request($request);        
            } else {
                return ['code'=>0,'message'=>'用户认证错误' ];
            }
        }else {
            return $this->continue_request($request);
        }
    }
}

/**
 * 修改密码 处理器
 * 修改数据库代码略。
 */
class ChangePassword extends Handler
{
    public function  handleRequest($request)
    {
        if ($request->url == 'change_password') {
            // 这里还可以继续检查参数是否正确,代码略
            return ['code'=>1,'data'=> 
                  "{$request->username}您好,密码修改成功,新密码是{$request->request_parameter['new_password']}"];
        }
        if ($this->successor) { // 直接把请求传递下去
            return $this->successor->handleRequest($request);
        }
        return ['code'=>0,'message'=>'url 不合法'];
    }
}

/**
 * 查粉丝,数据库代码用数组代替
 */
class QueryFans extends Handler
{
    protected $all_user;
    
    public function __construct(){
        $this->all_users = [
            'name1' =>'您的粉丝是name3,name4',
            'name2' => '您的粉丝是name5,name6,name7',
        ];
    }
    public function  handleRequest($request)
    {
        if ($request->url == 'query_fans') {
            if (array_key_exists( $request->username, $this->all_users )) {
                return ['code'=>1,'data'=> "{$request->username}您好,".
                   $this->all_users[ $request->username ] ];
            }else {
                return ['code'=>0,'message' =>'用户不存在' ];
            }
        }
        if ($this->successor) { // 直接把请求传递下去
            return $this->successor->handleRequest($request);
        }
        return ['code'=>0,'message'=>'url 不合法'];
    }
    
}

/**
 * 客户端代码,验证责任链设计模式
 */
class Client
{
    public function __construct(){
        
        $change_pass_handler = new ChangePassword();
        $query_handler = new QueryFans();
        $log_handler = new Log();
        $verification = new Verification();
        
        $log_handler->setSuccessor($verification);
        $verification->setSuccessor($change_pass_handler);
        $change_pass_handler->setSuccessor($query_handler);
        
        $request = new Request('luanxie_url', '', '', []);
        $result = $log_handler->handleRequest($request); // 把日志作为第一个处理器
        $this->print_result($result); 
        
        // 故意写错密码
        $request = new Request('change_password', 'name1', '1266', ['new_password'=>'124']);
        $result = $log_handler->handleRequest($request);
        $this->print_result($result);
        
        //故意写不存在 的用户
        $request = new Request('change_password', 'name444', '123', ['new_password'=>'124']);
        $result = $log_handler->handleRequest($request);
        $this->print_result($result);
        
        // 这次是符合规范的。
        $request = new Request('change_password', 'name1', '123', ['new_password'=>'124']);
        $result = $log_handler->handleRequest($request);
        $this->print_result($result);
        
        //粉丝查询,业务逻辑规定:不需要校验密码,写错也无所谓
        $request = new Request('query_fans', 'name1', '12789', []);
        $result = $log_handler->handleRequest($request);
        $this->print_result($result);
        
    }
        
    private function print_result($result)
    {
        if ($result['code']==1) {
            echo $result['data'];
        }else {
            echo $result['message'];  
        }
        echo  PHP_EOL.PHP_EOL;
    }
}

new Client();


结果展示

url:luanxie_url; request_parameter:[]
url 不合法

url:change_password; request_parameter:{"new_password":"124"}
用户认证错误

url:change_password; request_parameter:{"new_password":"124"}
用户认证错误

url:change_password; request_parameter:{"new_password":"124"}
name1您好,密码修改成功,新密码是124

url:query_fans; request_parameter:[]
name1您好,您的粉丝是name3,name4

0
0
分享到:
评论

相关推荐

    php设计模式之职责链模式定义与用法经典示例

    * @desc php设计模式之职责链模式(责任链模式) 定义:顾名思义,责任链模式为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。 在...

    Learning+PHP设计模式

    通过学习如何在代码中使用设计模式,可以更高效...第5部分 MySQL和PHP设计模式 第11章 通用类负责连接,代理模式保证安全 第12章 策略设计模式的灵活性 第13章 职责链设计模式 第14章 利用观察者模式构建多设备CMS

    php设计模式之职责链模式实例分析【星际争霸游戏案例】

    本文实例讲述了php设计模式之职责链模式。分享给大家供大家参考,具体如下: 星际的兵种属性随着对平衡性的调节,会进行修改。如果这样的话,我们就要考虑减少一个事件和具体处理的关联性。 比如一颗原子弹投下的...

    php设计模式 Chain Of Responsibility (职责链模式)

    php /** * 职责链模式 * * 为解除请求的发送者和接收者之间的耦合,而使用多个对象都用机会处理这个请求,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它 * */ abstract class Handler { ...

    LINUX网站建设技术指南

    第3章 配置TCP/IP网络 3.1 开始之前需要的信息 3.1.1 IP地址 3.1.2 网络掩码 3.1.3 网络地址(Network Address) 3.1.4 广播地址(Broadcast Address) 3.1.5 网关地址(Router/Gateway Address) 3.1.6 名字服务器...

Global site tag (gtag.js) - Google Analytics