命令模式
创建可被保存和传送的命令对象。
命令模式有助于系统更好进行组织,并有助于扩展。
命令对象的接口极为简单,因为他只要求实现一个方法execute()。命令模式有三部分组成:实例化命令对象的客户端(client)、部署命令对象的调用者(invoker)和接受命令对象的接收者(receiver)。
让我们创建一个具体的Command类:
abstract class Command
{
abstract function execute(CommandContext $context);
}
class LoginCommand extends Command
{
function execute(CommandContext $context)
{
$manager = Registry::getAccessManager();
$user = $context->get('username');
$pass = $context->get('pass');
$user_obj = $manager->login($user, $pass);
if (is_null($user_obj)) {
$context->setError($manager->getError());
return false;
}
$context->addParam("user", $user_obj);
return true;
}
}
LoginCommand被设计为与AccessManager(访问管理器)对象一起工作。AccessManager是一个虚构出来的类,它的任务就是处理用户登录系统的具体细节。
下面是一个简单的CommandContext实现:
class CommandContext
{
private $params = array();
private $error = "";
function __construct()
{
$this->params = $_REQUEST;
}
function addParam($key, $val)
{
$this->params[$key] = $val;
}
function get($key)
{
return $this->params[$key];
}
function setError($error)
{
$this->error = $error;
}
function getError()
{
return $this->error;
}
}
现在我们仍然缺少客户端代码(即用于创建命令对象的类)及调用者类(使用生成的命令的类)。
class CommandNotFoundException extends Exception
{
}
class CommandFactory
{
private static $dir = 'commands';
static function getCommand($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 CommandNotFoundException("could not find '$file'");
}
require_once($file);
if (!class_exists($class)) {
throw new CommandNotFoundException("no '$class' class located");
}
$cmd = new $class();
return $cmd;
}
}
CommandFactory类在commands目录里查找特定的类文件。
下面是一个简单的调用者:
class Controller
{
private $context;
function __construct()
{
$this->context = new CommandContext();
}
function getContext()
{
return $this->context;
}
function process()
{
$cmd = CommandFactory::getCommand($this->context->get('action'));
if (!$cmd->execute($this->context)) {
//处理失败
} else {
//成功
//现在分发视图
}
}
}
$controller = new Controller();
//伪造用户请求
$context = $controller->getContext();
$context->addParam('action', 'login');
$context->addParam('username', 'bob');
$context->addParam('pass', 'tiddles');
$controller->process();
让我们再创建一个Command类:
class FeedbackCommand extends Command
{
function execute(CommandContext $context)
{
$msgSystem = Registry::getMessageSystem();
$email = $context->get('email');
$msg = $context->get('msg');
$topic = $context->get('topic');
$result = $msgSystem->send($email, $msg, $topic);
if (!$result) {
$context->setError($msgSystem->getError());
return false;
}
return true;
}
}
下图展示命令模式的各个部分: