意圖
將一個請求封裝爲一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可取消的操作
適用性
- 像上面討論的MenuItem對象那樣,抽象出待執行的動作以參數化某對象。你可用過程語言中的回調(callback)函數表達這種參數化機制。所謂回調函數是指函數先在某處註冊,而它將在稍後某個需要的時候被調用。Command模式是回調機制的一個面向對象的替代品。
- 在不同的時刻指定、排列和執行請求。一個Command對象可以有一個與初始請求無關的生存期。如果一個請求的接收者可用一種與地址空間無關的方式表達,那麼就可將負責該請求的命令對象傳送給另一個不同的進程並在那兒實現該請求。
- 支持取消操作。Command的Execute操作可在實施操作前將狀態存儲起來,在取消操作時這個狀態用來消除該操作的影響。Command接口必須添加一個Execute操作,該操作取消上一次Execute調用的效果。執行的命令被存儲在一個歷史列表中。可通過向後和向前遍歷這一列表並分別調用Unexecute和Execute來實現重數不限的“取消”和“重做”。
- 支持修改日誌,這樣當系統崩潰時,這些修改可以被重做一遍。在Command接口中添加裝載操作和存儲操作,可以用來保持變動的一個一致的修改日誌。從崩潰中恢復的過程包括從磁盤中重新讀入記錄下來的命令並用Execute操作重新執行它們。
- 用構建在原語操作上的高層操作構造一個系統。這樣一種結構在支持事務(Transaction)的信息系統中很常見。一個事務封裝了對數據的一組變動。Command模式提供了對事務進行建模的方法。Command有一個公共的接口,使得你可以用同一種方式調用所有的事務。同時使用該模式也易於添加新事務以擴展系統。
Java實現
接收者角色類
public class Receiver {
/**
* 真正執行命令相應的操作
*/
public void action(){
System.out.println("執行操作");
}
}
抽象命令角色類
public interface Command {
/**
* 執行方法
*/
void execute();
}
具體命令角色類
public class ConcreteCommand implements Command {
//持有相應的接收者對象
private Receiver receiver = null;
/**
* 構造方法
*/
public ConcreteCommand(Receiver receiver){
this.receiver = receiver;
}
@Override
public void execute() {
//通常會轉調接收者對象的相應方法,讓接收者來真正執行功能
receiver.action();
}
}
請求者角色類
public class Invoker {
/**
* 持有命令對象
*/
private Command command = null;
/**
* 構造方法
*/
public Invoker(Command command){
this.command = command;
}
/**
* 行動方法
*/
public void action(){
command.execute();
}
}
客戶端角色類
public class Client {
public static void main(String[] args) {
//創建接收者
Receiver receiver = new Receiver();
//創建命令對象,設定它的接收者
Command command = new ConcreteCommand(receiver);
//創建請求者,把命令對象設置進去
Invoker invoker = new Invoker(command);
//執行方法
invoker.action();
}
}
Clojure實現
還是first-class function!!!
代碼可以直接參考橋接模式