创建可被保存和传送的命令对象。
命令模式有助于系统更好进行组织,并有助于扩展。
命令对象的接口极为简单,因为他只要求实现一个方法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; } }下图展示命令模式的各个部分:
