我的
设计模式系列文章
php设计模式(1)--
观察者模式 -- spl标准写法
php设计模式(2)-- 观察者模式 -- 用trait来改进的写法
php设计模式(3)--
责任链(职责链)模式
php设计模式(4)-- 装饰器模式
这次讨论责任链。
分析
实际上,责任链很想象软件开发中的中间件,请求只有一个,但是会有很多处理对象,每个处理对象都包含下一个对象,每个处理对象都有权处理。
主要角色,处理类,以及其共同
接口
次要角色,请求对象。
网上的代码很多,主要是一个员工请假的需求,太
无聊了。下面我构造一个需求,假设请求是用户想要修改他自己的密码,于是请求对象包含请求url,用户名,原密码,新密码。
还有一个需求,用户检查他的
粉丝,不需要登录校验。
在处理过程中,我会记录所有请求的日志,这里使用一个处理类。
在处理过程中,有些请求需要校验用户密码,有些不需要,这是登录验证请求。
在处理过程中,如果请求url
错误,会报告错误。
所以总共是日志
处理器,登录校验处理器,密码修改处理器,查询粉丝处理器。
经验体会,该模式可以有返回值,也可以没有返回值。随意。
经验2:构造责任处理器链,是在客户端代码中,请注意这一点。
代码实现
class="php" name="code">
<?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