对于这种请求-分发式的任务需求,command模式再适合不过了。通过把用户不同请求封装为对象保证了系统单一入口方式,另一方面在增加新任务的时候程序结构会变得清晰简单。现在访问PHP页面的时候,更倾向于提供参数明确告诉系统所要执行的功能,而不是把不同的请求自由分散到不同的PHP子文件中。
命令模式由几部分组成:命令对象、实例化命令对象的命令工厂(commmand factory)、触发命令对象的控制器(controller)、命令对象的接收者(完成具体的业务逻辑)、部署命令对象的客户端。
对于传统的任务请求流程大致如下:
$params = $_REQUEST['cmd'];//保存参数
$ret = do_task($params); //任务执行
echo $ret; //反馈结果
这里主要存在如下几个问题:
command模式提供了一个上下文相关的参数类(context),完成了参数传递。不同的命令对象统一从context类取出参数,并把执行结果通过context类返回给上层。
context的实现如下:
class CommandContext{
private $params = array();
private $result = "";
public function __construct(){
$params = $_REQUEST;
}
public function add_param($key, $value){
$this->params[$key] = $value;
}
public function get_param($key){
$this->params[$key];
}
public function set_result($result){
$this->result = $result;
}
public function get_result(){
return $this->result;
}
}
command类:
abstract class Command(){
abstract public function execute(CommandContex $context);
}
前端用户登录命令:
class LoginCommand extends Command {
public function execute(CommandContext $context){
$ret = true;
do
{
//获取具体处理命令的对象
$UserManager = Registry::get_user_manager();
if(!isset($UserManager)){
$ret = false;
$context->set_error("could not found registry object");
break;
}
//获取参数
$username = $context->get_param('username');
$password = $context->get_param('password');
//执行操作
$user = $UserManager->login($username, $password);
//返回结果
if(is_null($user)){
$context->set_error($UserManager->error());
$ret = false;
break;
} else{
$context->add_param('user', $user);
}
}while(0);
return $ret;
}
}
在这里通过静态方法构建命令的接受对象,这样保证了execute接口参数简单化。另外也可以通过把命令接受对象传递给命令对象。
接下来实现命令工厂:
class CommandFactory {
private static $dir = "commands";
public function get_command($action="Default"){
if(preg_match('/\W/', $action)) {
throw new Exception('illegal characters in action');
}
$class = UCFirst(strtolower($action))."Command";
$file = self::$dir . DIRECTORY_SEPARATOR."{$class}.php";
if(!file_exists($file)){
throw new Exception('not found command class file');
}
require_once($file);
if(!class_exists($class)){
throw new Exception('n
function triggle(){ot found command class');
}
$cmd = new $class();
return $cmd;
}
}
把命令对象文件放在commands文件夹下,根据不同的请求加载不同的命令对象文件,并构建对象。
触发命令对象的控制器(controller)的实现:
class Controller{
private $context;
public function __construct(){
$context = new CommandContext();
}
public function get_context(){
return $this->context;
}
public function process(){
$command = CommandFactory::get_command($this->context->get_param('action'));
if($command->execute($this->context)){
//ok
} else {
//fail
}
return;
}
}
最后是部署命令对象的客户端
class Client{
function triggle(){
$controller = new Controller();
$context = $controller->get_context();
$context->add_param('action', 'login');
$context->add_param('username', 'lufy');
$context->add_param('userpassword', '123456');
$controller->process();
}
}
The end.