命令模式描述:
命令模式的理解
生活中例子:
例子1: 上路边摊吃烤串,和上烤串店吃烤串比较,门店更加好点不容易算错帐,不容易记错客户的要求,等等。
门店中 客户,服务点, 厨师的关系对照设计模式术语怎么理解? 厨师 ===执行类(会烤鱼,烤串,等等); 服务员== 传达命令类/表面执行类(相会客户来说); 菜单=== 命令类; 客户=== 使用命令的地方;
简单的命令模式代码如下:
<?php
interface Command{
function execute();
}
//具体命令角色,指定接受者执行攻击命令
class AttackCommand implements Command{
private $receiver;
function __construct(Receiver $receiver)
{
$this->receiver = $receiver;
}
function execute()
{
// TODO: Implement execute() method.
$this->receiver->attackAction();
}
}
//具体名利角色,指定接受者执行防御命令
class DefenseCommand implements Command{
private $receiver;
function __construct(Receiver $receiver)
{
$this->receiver = $receiver;
}
function execute()
{
// TODO: Implement execute() method.
$this->receiver->defenseAction();
}
}
//接受者,执行具体命令角色的命令
class Receiver{
private $name;
function __construct($name)
{
$this->name = $name;
}
function attackAction(){
echo $this->name."执行了攻击命令\n";
}
function defenseAction(){
echo $this->name."执行了防御命令\n";
}
}
//请求者,请求具体命令的执行
class Invoker{
private $concreteCommand;
function __construct($concreteCommand)
{
$this->concreteCommand = $concreteCommand;
}
function executeCommand(){
$this->concreteCommand->execute();
}
}
//客户端角色
class Client{
function __construct()
{
$receiverZhao = new Receiver("小明");
$attackCommand = new AttackCommand($receiverZhao);
$attackInvoker = new Invoker($attackCommand);
$attackInvoker->executeCommand();
$receiverYe = new Receiver("小丽");
$defenseCommand = new DefenseCommand($receiverYe);
$defenseInvoker = new Invoker($defenseCommand);
$defenseInvoker->executeCommand();
}
}
new Client();
较复杂命令模式如下:
比较上面增加就是 对命令集支持,可以增加,或删除命令,并且同时execute执行多个命令
<?php
interface Command{
public function execute();
}
/**
* 多命令接口
*/
interface MacroCommand extends Command{
/**
* @param Command $command
* @return mixed
* 删除一个成员命令
*/
public function remove(Command $command);
/**
* @param Command $command
* @return mixed
* 增加一个成员命令
*/
public function add(Command $command);
}
class DemoMacroCommand implements MacroCommand{
private $_commandList;
public function __construct()
{
$this->_commandList = array();
}
public function remove(Command $command)
{
// TODO: Implement remove() method.
$key = array_search($command, $this->_commandList);
if($key === FALSE){
return false;
}
unset($this->_commandList[$key]);
return true;
}
public function add(Command $command){
return array_push($this->_commandList,$command);
}
public function execute()
{
// TODO: Implement execute() method.
foreach($this->_commandList as $command){
$command->execute();
}
}
}
class CopyCommand implements Command{
private $_receiver;
public function __construct(Receiver $receiver)
{
$this->_receiver = $receiver;
}
/**
* 执行方法
*/
public function execute()
{
// TODO: Implement execute() method.
$this->_receiver->copy();
}
}
class PasteCommand implements Command{
private $_receiver;
public function __construct(Receiver $receiver)
{
$this->_receiver = $receiver;
}
public function execute()
{
// TODO: Implement execute() method.
$this->_receiver->paste();
}
}
/**
* Class Receiver
* 接受者角色
*/
class Receiver{
/*接收者名称*/
private $_name;
public function __construct($name)
{
$this->_name = $name;
}
/**
* 复制方法
*/
public function copy(){
echo $this->_name, "do copy action.\n";
}
/**
* 粘贴方法
*/
public function paste(){
echo $this->_name, "do paste action.\n";
}
}
/**
* 请求者角色
*/
class Invoker{
private $_command;
public function __construct(Command $command)
{
$this->_command = $command;
}
public function action(){
$this->_command->execute();
}
}
/**
* Class Client
* 客户端
*/
class Client{
public static function main(){
$receiver = new Receiver('小李');
$pasteCommand = new PasteCommand($receiver);
$copyCommand = new CopyCommand($receiver);
$macroCommand = new DemoMacroCommand();
$macroCommand->add($copyCommand);
$macroCommand->add($pasteCommand);
$invoker = new Invoker($macroCommand);
$invoker->action();
$macroCommand->remove($copyCommand);
$invoker->action();
}
}
Client::main();
实际上,一个命令可能需要占用单独的一个文件,这些后就需要一个类或函数负责 加载文件,判断类是否存在等。
代码如下:
<?php
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 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;
}
}
class CommandNotFoundException extends Exception{}
class Controller {
private $context;
function __construct()
{
$this->context = new CommandContext();
}
/**
* @return CommandContext
*/
public function getContext()
{
return $this->context;
}
function process(){
$cmd = CommandFactory::getCommand($this->context->get('action'));
if(! $cmd->execute($this->context)){
//处理失败
}else {
//成功
//现在分发试图
print "success";
}
}
}
$controller = new Controller();
$context = $controller->getContext();
//伪造用户请求
$context -> addParam('action','login');
$context -> addParam('username','bob');
$context -> addParam('pass','tiddles');
$controller -> process();
LoginCommand.php 如下:
<?php
abstract class Command{
abstract function execute(CommandContext $context);
}
class LoginCommand extends Command{
function execute(CommandContext $context)
{
// TODO: Implement execute() method.
//$manager = Registry::getAccessManager();
$manager = new Manager();
$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中
class Manager{
private $error;
function login($user, $pass){
//从数据中查找比对
return true;
}
function getError(){
return $this->error;
}
}