命令模式

問題:
若是頁面必須處理不少不一樣的任務,就應該考慮將任務進行封裝。封裝以後,向系統中增長新任務就會變得簡單,而且能夠將系統中的各部分分離開來。這時,咱們就可使用命令模式了。php

概念:
將一個請求封裝爲一個對象,從而使你能夠用不一樣的請求對客戶進行參數化,對請求排隊或記錄請求日誌,以及支持可撤銷的操做。緩存

實現:
1. 類圖示例:測試

2. 代碼示例:ui

//命令對象參數類
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對象不該該執行太多的邏輯。它們應該負責檢查輸入、處理錯誤、緩存對象和調用其餘對象來執行一些必要的操做。this

效果:
1. 能比較容易地設計一個命令隊列。
2. 在須要的狀況下,能夠較容易地將命令記入日誌。
3. 容許接收請求的一方決定是否要否決請求。
4. 能夠很容易地實現對請求的撤銷和重作。
5. 因爲加進新的具體命令類不影響其餘的類,所以增長新的具體命令類很容易。
6. 促進了控制器和領域模型的分離。
7. 更好地組織系統,易於擴展。spa

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息