<?php
/*
(1)命令模式定义
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作
命令模式的经典应用在于图形界面的菜单功能,其本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开来,
所以命令发起者不必要知道命令执行者的接口以及命令具体的执行细节。
(1)Command:
定义命令的接口,声明执行的方法。
(2)ConcreteCommand:
命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
(3)Receiver:
接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
(4)Invoker:
要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
(5)Client:
创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。
虽然命令模式源于图形界面设计,但其在PHP中也很常用,例如我们现在很多系统都倾向于将所有请求的入口集中到一个地方,运用路由器的思路,
在这个统一的入口去做具体请求执行的分发,这个入口一般是index.php。下面我们先比较一下两种不同方式的URL:
*/
// (1)Command
interface ActionInterface{
public function execute();
}
//具体Action的超类,在标准的Command模式中并没有这一层抽象,完全是根
//据具体业务需求来确定的,这里的超类复制处理所有具体Action的通用操作
//(2) ConcreteCommand
class Action implements ActionInterface{
private $request;
private $response;
//这里将请求数据封装为MyRequest对象,返回封装为MyResponse对象
//其实就是相当于模式中的命令接收者,只不过这里为了区分封装成两个对象了
public function __construct(MyRequest $request, MyResponse $response){
$this->request = $request;
$this->response = $response;
}
//这个方法需要具体的Action去实现
public abstract function execute();
}
//用户登录Action,也就是模式中的Concrete Command
class UserLogin extends Action{
public function execute(){
$username = $this->request->post('username');
$password = $this->request->post('password');
//实际项目中这里肯定要读取数据库,这里简便处理
if ($username=='admin' && $password=="111111"){
$response->assign('status', true);
}else{
$response->assign('status', false));
}
$response->render("user/login.php");
}
}
//发布贴子Action,这里省略具体代码,结构和UserLogin Action一致,只是具体逻辑不一样
class AddPost extends Action{
//......
}
//(3)Receiver:
//MyRequest和MyResponse对象,也就是模式中的命令接收者
//MyRequest对象负责处理数据输入,实际上的处理逻辑肯定比这里复杂,这里只做简单实现
class MyRequest{
private $get;
private $post;
public function __construct(){
$this->get = $_GET;
$this->post = $_POST;
}
//获取GET参数
public function get($name){
return $this->get[$name];
}
//获取POST参数
public function post($name){
return $this->post[$name];
}
}
//MyResponse负责处理数据输出,这里也只做简单实现
class MyResponse{
private $data;
//缓存需要输出的数据
public function assign($name, $value){
$this->data[$name] = $value;
}
//视图输出;实际项目中可能还有纯文本输出(text),JSON格式输出,XML格式输出等等
public function render($view){
//使用到缓存的$data数据进行输出,这里简单引用视图PHP文件,具体怎么输出这里不赘述了
require($view);
}
}
//命令调用者,实现了路由功能。经典范例中,调用者不负责具体命令的初始化,只负责执行
//已经记录执行的过程(方便做undo得操作),我们这里稍作调整,主要为了实现路由功能
//假设我们这里使用 index.php?action=user/login 的方式,不用rewrite就能测试
class Router{
public static function route(){
//初始化命令接收者
$request = new MyRequest();
$response = new MyResponse();
//查询并初始化具体的命令,这里省略了错误处理,比如空action参数,文件不存在,类不存在等
$actionName = $request->get('action');
$actionClass = implode("_", array_walk(explode("/", $action), "ucfirst"));
require($actionClass.".php");//实际项目中推荐使用SPL Autoloader方式载入
$action = new $actionClass($request, $response);
//执行命令
$action->execute();
}
}
//入口index.php
<?php
require("Router.php");
Router::route();
php中的设计模式之--命令模式
最新推荐文章于 2024-01-11 15:58:04 发布