• 命令模式


    问题:
    如果页面必须处理很多不同的任务,就应该考虑将任务进行封装。封装之后,向系统中增加新任务就会变得简单,并且可以将系统中的各部分分离开来。这时,我们就可以使用命令模式了。

    概念:
    将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

    实现:
    1. 类图示例:

    2. 代码示例:

    //命令对象参数类
    class CommandContext
    {
    	private $params = [];
    	private $error = '';
    
    	public function __construct()
    	{
    		$this->params = $_REQUEST;
    	}
    
    	public function addParam($key, $val)
    	{
    		$this->params[$key] = $val;
    	}
    
    	public function get($key)
    	{
    		return $this->params[$key];
    	}
    
    	public function setError($error)
    	{
    		$this->error = $error;
    	}
    
    	public function getError()
    	{
    		return $this->error;
    	}
    }
    //命令对象基类
    abstract class Command
    {
    	abstract public function execute(CommandContext $context);
    }
    //命令对象具体实现
    class LoginCommand extends Command
    {
    	public function execute(CommandContext $context)
    	{
    		$manager = Registry::getAccessManager();
    		$user = $context->get('username');
    		$pass = $context->get('pass');
    		$userObj = $manager->login($user, $pass);
    		if(is_null($userObj)) {
    			$context->setError($manager->getError());
    			return false;
    		}
    		$context->addParam('user', $userObj);
    		return true;
    	}
    }
    //命令对象具体实现
    class FeedbackCommand extends Command
    {
    	public 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;
    	}
    }
    //命令对象异常类
    class CommandNotFoundException extends Exception {}
    //命令对象工厂类
    class CommandFactory
    {
    	private static $dir = 'commands';
    
    	public 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('file not found: ' . $file);
    		}
    		require_once($file);
    		if(!class_exists($class)) {
    			throw new CommandNotFoundException('class not found: ' . $file);
    		}
    		$cmd = new $class();
    		return $cmd;
    	}
    }
    //命令对象调用者
    class Controller
    {
    	private $context;
    
    	public function __construct()
    	{
    		$this->context = new CommandContext();
    	}
    
    	public function getContext()
    	{
    		return $this->context;
    	}
    
    	public 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', 'jet');
    $context->addParam('pass', '888888');
    $controller->process();
    

    注意:Command对象不应该执行太多的逻辑。它们应该负责检查输入、处理错误、缓存对象和调用其他对象来执行一些必要的操作。

    效果:
    1. 能比较容易地设计一个命令队列。
    2. 在需要的情况下,可以较容易地将命令记入日志。
    3. 允许接收请求的一方决定是否要否决请求。
    4. 可以很容易地实现对请求的撤销和重做。
    5. 由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易。
    6. 促进了控制器和领域模型的分离。
    7. 更好地组织系统,易于扩展。

  • 相关阅读:
    linux在线安装jdk,tomcat,Nginx
    SpringAOP的实现方式
    Spring整合Mybatis
    基本sql语句
    解决No module named 'sklearn.cross_validation'
    虚拟机中安装redhat8操作系统
    【Linux命令】tcpdump抓包工具
    【Nodejs】Linux系统搭建Nodejs
    【SSL证书配置】tomcat实现SSL证书访问
    【SSL证书配置】腾讯云申请ssl证书,nginx+tomcat配置ssl证书
  • 原文地址:https://www.cnblogs.com/wujuntian/p/9658420.html
Copyright © 2020-2023  润新知