設計模式--命令模式Command(行為型)
1.概述
在軟體設計中,我們經常需要向某些物件傳送請求,但是並不知道請求的接收者是誰,也不知道被請求的操作是哪個,我們只需在程式執行時指定具體的請求接收者即可,此時,可以使用命令模式來進行設計,使得請求傳送者與請求接收者消除彼此之間的耦合,讓物件之間的呼叫關係更加靈活。例子1:電視機遙控器 : 遙控器是請求的傳送者,電視機是請求的接收者,遙控器上有一些按鈕如開,關,換頻道等按鈕就是具體命令,不同的按鈕對應電視機的不同操作。
在軟體系統中,“行為請求者”與“行為實現者”通常呈現一種“緊耦合”。但在某些場合,比如要對行為進行“記錄、撤銷/重做、事務”等處理,這種無法抵禦變化的緊耦合是不合適的。在這種情況下,如何將“行為請求者”與“行為實現者”解耦?
命令模式(Command Pattern):將一個請求封裝為一個物件,從而使我們可用不同的請求對客戶進行引數化;對請求排隊或者記錄請求日誌,以及支援可撤銷的操作。命令模式又稱為動作(Action)模式或事務(Transaction)模式。(Command Pattern: Encapsulate a request asan object, thereby letting youparameterize clients withdifferent requests,queueor log requests,andsupportundoable operations. )
1)系統需要將請求呼叫者和請求接收者解耦,使得呼叫者和接收者不直接互動。2)系統需要在不同的時間指定請求、將請求排隊和執行請求。3)系統需要支援命令的撤銷(Undo)操作和恢復(Redo)操作。4)系統需要將一組操作組合在一起,即支援巨集命令。
抽象命令類(Command): 宣告執行操作的介面。呼叫接收者相應的操作,以實現執行的方法Execute。具體命令類(ConcreteCommand): 建立一個具體命令物件並設定它的接收者。通常會持有接收者,並呼叫接收者的功能來完成命令要執行的操作。呼叫者(Invoker): 要求該命令執行這個請求。通常會持有命令物件,可以持有很多的命令物件。接收者(Receiver): 知道如何實施與執行一個請求相關的操作。任何類都可能作為一個接收者,只要它能夠實現命令要求實現的相應功能。客戶類(Client): 建立具體的命令物件,並且設定命令物件的接收者。真正使用命令的客戶端是從Invoker來觸發執行。
7.效果
Command模式優點:
1) 降低系統的耦合度:Command模式將呼叫操作的物件與知道如何實現該操作的物件解耦。
2) Command是頭等的物件。它們可像其他的物件一樣被操縱和擴充套件。
3) 組合命令:你可將多個命令裝配成一個組合命令,即可以比較容易地設計一個命令佇列和巨集命令。一般說來,組合命令是Composite模式的一個例項。
4) 增加新的Command很容易,因為這無需改變已有的類。
5)可以方便地實現對請求的Undo和Redo。
命令模式的缺點:
使用命令模式可能會導致某些系統有過多的具體命令類。因為針對每一個命令都需要設計一個具體命令類,因此某些系統可能需要大量具體命令類,這將影響命令模式的使用。
8.實現
電視機遙控器 :
電視機是請求的接收者,
遙控器是請求的傳送者,
遙控器上有一些按鈕,不同的按鈕對應電視機的不同操作。抽象命令角色由一個命令介面來扮演,
有三個具體的命令類實現了抽象命令介面,這三個具體命令類分別代表三種操作:開啟電視機、關閉電視機和切換頻道。
顯然,電視機遙控器就是一個典型的命令模式應用例項。
<?php /** * 電視機遙控器 : 電視機是請求的接收者, 遙控器是請求的傳送者, 遙控器上有一些按鈕,不同的按鈕對應電視機的不同操作。抽象命令角色由一個命令介面來扮演, 有三個具體的命令類實現了抽象命令介面,這三個具體命令類分別代表三種操作:開啟電視機、關閉電視機和切換頻道。 顯然,電視機遙控器就是一個典型的命令模式應用例項。 */ /** * The Command abstraction( 命令介面,宣告執行的操作). * In this case the implementation must return a result, * sometimes it only has side effects. */ interface ICommand { /** * 執行命令對應的操作 * * @param unknown_type $name * @param unknown_type $args */ function execute(); } /** * ConcreteCommand具體的命令實現物件:開啟命令 */ class ConcreteCommandOpen implements ICommand { /** * 持有相應的接收者物件 */ private $_receiverTV = null; // /** * 示意,命令物件可以有自己的狀態 */ private $_state; /** * 構造方法,傳入相應的接收者物件 * @param receiver 相應的接收者物件 */ public function __construct($receiver){ $this->_receiverTV = $receiver; } public function execute() { //通常會轉調接收者物件的相應方法,讓接收者來真正執行功能 $this->_receiverTV->actionOpen(); } } /** * ConcreteCommand具體的命令實現物件:關閉 */ class ConcreteCommandClose implements ICommand { /** * 持有相應的接收者物件 */ private $_receiverTV = null; // /** * 示意,命令物件可以有自己的狀態 */ private $_state; /** * 構造方法,傳入相應的接收者物件 * @param receiver 相應的接收者物件 */ public function __construct($receiver){ $this->_receiverTV = $receiver; } public function execute() { //通常會轉調接收者物件的相應方法,讓接收者來真正執行功能 $this->_receiverTV->actionClose(); } } /** * ConcreteCommand具體的命令實現物件:換頻道 */ class ConcreteCommandChange implements ICommand { /** * 持有相應的接收者物件 */ private $_receiverTV = null; // /** * 示意,命令物件可以有自己的狀態 */ private $_state; /** * 構造方法,傳入相應的接收者物件 * @param receiver 相應的接收者物件 */ public function __construct($receiver){ $this->_receiverTV = $receiver; } public function execute() { //通常會轉調接收者物件的相應方法,讓接收者來真正執行功能 $this->_receiverTV->actionChange(); } } /** * 接收者物件 */ class ReceiverTV { /** * 真正執行命令相應的開啟操作 */ public function actionOpen(){ echo 'actionOpen<br/>'; } /** * 真正執行命令相應的關閉操作 */ public function actionClose(){ echo 'actionClose<br/>'; } /** * 真正執行命令相應的換頻道操作 */ public function actionChange(){ echo 'actionChange<br/>'; } } /** * 呼叫者Invoker:遙控器 */ class InvokerControler { /** * 持有命令物件 */ private $_commands = null; //ICommand /** * 設定呼叫者持有的命令物件 * @param command 命令物件 */ public function addCommand($command) { $classname = get_class($command); $this->_commands[$classname] = $command; } /** * 示意方法,要求命令執行請求 */ public function runCommand($cmdName) { //呼叫命令物件的執行方法 $this->_commands[$cmdName]->execute(); } } class Client { /** * 示意,負責建立命令物件,並設定它的接收者 */ public static function main(){ //建立電視接收者 $receiver = new ReceiverTV(); //建立Invoker $invoker = new InvokerControler(); //建立命令物件,設定它的接收者 $commandOpen = new ConcreteCommandOpen($receiver); //把命令物件設定進呼叫遙控器 $invoker->addCommand($commandOpen); //執行開啟命令 $invoker->runCommand(get_class($commandOpen)); } } Client::main(); ?>
UML圖:巨集命令又稱為組合命令,它是命令模式和組合模式聯用的產物:巨集命令也是一個具體命令,不過它包含了對其他命令物件的引用,在呼叫巨集命令的execute()方法時,將遞迴呼叫它所包含的每個成員命令的execute()方法,一個巨集命令的成員物件可以是簡單命令,還可以繼續是巨集命令。執行一個巨集命令將執行多個具體命令,從而實現對命令的批處理。Ÿ
9.與其他相關模式
1)Composite模式(可被用來實現巨集命令。
2)備忘錄Memento模式可用來保持某個狀態,命令用這一狀態來取消它的效果。在被放入歷史表列前必須被拷貝的命令起到一種原型的作用。
10.總結與分析
2)每一個命令都是一個操作:請求的一方發出請求,要求執行一個操作;接收的一方收到請求,並執行操作4)命令模式使請求本身成為一個物件,這個物件和其他物件一樣可以被儲存和傳遞。5)命令模式的關鍵在於引入了抽象命令介面,且傳送者針對抽象命令介面程式設計,只有實現了抽象命令介面的具體命令才能與接收者相關聯。
相關文章
- JavaScript設計模式--行為型別--命令模式JavaScript設計模式型別
- 設計模式-命令模式(Command)設計模式
- 設計模式——18命令模式(Command)設計模式
- Java設計模式(22)命令模式(Command模式)Java設計模式
- 設計模式-行為型設計模式
- 行為型設計模式設計模式
- C++設計模式——命令模式(command pattern)C++設計模式
- C#設計模式系列:命令模式(Command)C#設計模式
- JAVA設計模式之 命令模式【Command Pattern】Java設計模式
- 設計模式--策略模式Strategy(行為型)設計模式
- 行為型命令模式模式
- 設計模式(十九)----行為型模式之命令模式設計模式
- 4/24 設計模式之命令設計模式 Command Pattern設計模式
- 設計模式的征途—19.命令(Command)模式設計模式
- 設計模式:命令模式(Command Pattern)及例項設計模式
- (Java)設計模式:行為型Java設計模式
- 設計模式之中介者模式(行為型)設計模式
- 設計模式--狀態模式State(行為型)設計模式
- 設計模式--迭代器模式Iterator(行為型)設計模式
- 設計模式--中介者模式Mediator(行為型)設計模式
- 聊一聊設計模式(四)-- 行為型設計模式設計模式
- 【圖解設計模式系列】The Command Pattern: 命令列模式圖解設計模式命令列
- 行為型設計模式 - 狀態模式詳解設計模式
- 行為型設計模式 - 觀察者模式詳解設計模式
- 設計模式-- 觀察者模式Observer(物件行為型)設計模式Server物件
- PHP行為型設計模式(四)PHP設計模式
- PHP行為型設計模式(三)PHP設計模式
- PHP 行為型設計模式(二)PHP設計模式
- PHP 行為型設計模式(一)PHP設計模式
- 行為型設計模式 - 備忘錄模式詳解設計模式
- 行為型設計模式 - 責任鏈模式詳解設計模式
- 設計模式--責任鏈模式ChainOfResponsibility(行為型)設計模式AI
- 設計模式--模板方法模式Template method(類行為型)設計模式
- 設計模式--備忘錄模式Memento(行為型)設計模式
- 設計模式--訪問者模式Visitor(行為型)設計模式
- 命令模式與go-redis command設計模式GoRedis
- 大話 PHP 設計模式--行為型PHP設計模式
- 物件導向-設計模式-行為型物件設計模式