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