命令模式屬于23種設計模式中行為模式中的一個,它也是一種簡單實用非常普遍的設計模式。
首先看下GOF對命令模式的定義:將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求日志,以及支持可撤銷的操作。
命令模式主要應用于將行為調用者與實現者解耦。比如我們以前慣用的寫代碼的方式是LogicProcess logic = new LogicProcess(); 然后緊接著調用實現方法logic.process(),這種寫法其實非常普遍,但這種寫法把行為調用者和行為實現者耦合在了一起,一般情況下并沒有什么問題的,但當調用邏輯比較復雜或則調用行為有多種實現時就非常不利于程序的擴展。
命令模式的適用場景描述:
(1)整個調用過程比較繁雜,或者存在多處這種調用。使用Command類對該調用加以封裝,便于功能的再利用。
(2)調用前后需要對調用參數進行某些處理。
(3)調用前后需要進行某些額外處理,比如日志,緩存,記錄歷史操作等。
命令模式結構圖如下:
wKioL1MXQNnzDmOuAAE_6jCA_qk028.jpg
命令模式的參與角色:
(1)抽象命令角色(Command):抽象命令,包含命令執行的抽象方法
(2)命令接收者(Receiver):命令接收者角色,它包含所有命令的具體行為實現方法。
(3)具體命令角色(ConcreteCommand):它包含一個命令接收者對象,并調用接收者的對象相應實現方法。
(4)命令調用者角色(Invoker):提供給客戶端調用,接收客戶端所傳遞的具體命令對象。
下面看具體代碼實現:
1、第一個文件抽象命令角色:Command.java
/**
* 抽象命令接口
*/
public interface Command {
/**
* 命令執行方法
*/
public void execute();
}
2、第二個文件命令接收者角色:Document.java
/**
* 命令接收者 Receiver
*/
public class Document {
/**
* 操作實體對象
*/
public static StringBuffer sbr = new StringBuffer();
/**
* 計數器
*/
public static int count = 0;
/**
* 撤銷實現方法
*/
public void undo(){
System.out.println("調用撤銷實現方法,字符串遞減");
sbr.deleteCharAt(sbr.length()-1);
count --;
System.out.println("當前文本為:" + sbr.toString());
}
/**
* 恢復實現方法
*/
public void redo(){
System.out.println("調用恢復實現方法,字符串遞加");
this.sbr.append(count);
count ++;
System.out.println("當前文本為:" + sbr.toString());
}
/**
* 執行實現方法
*/
public void add(){
System.out.println("調用執行實現方法,字符串遞加");
this.sbr.append(count);
count ++;
System.out.println("當前文本為:" + sbr.toString());
}
}
3、第三個文件具體命令角色:AddCommand.java
/**
* 執行命令實現類
*/
public class AddCommand implements Command {
/**
* 命令接受者對象
*/
public Document doucment;
/**
* 構造方法
* @param document
*/
public AddCommand(Document document){
this.doucment = document;
}
@Override
public void execute() {
// TODO Auto-generated method stub
this.doucment.add();
}
4、第四個文件具體命令角色:UndoCommand.java
/**
* 撤銷命令實現類
*/
public class UndoCommand implements Command {
/**
* 命令接受者對象
*/
public Document doucment;
/**
* 構造方法
* @param document
*/
public UndoCommand(Document document){
this.doucment = document;
}
@Override
public void execute() {
// TODO Auto-generated method stub
this.doucment.undo();
}
}
5、第五個文件具體命令角色:RedoCommand.java
/**
* 恢復命令實現類
*/
public class RedoCommand implements Command {
/**
* 命令接受者對象
*/
public Document doucment;
/**
* 構造方法
* @param document
*/
public RedoCommand(Document document){
this.doucment = document;
}
@Override
public void execute() {
// TODO Auto-generated method stub
this.doucment.redo();
}
}
6、第六個文件調用者角色:Invoker.java
/**
* 提供給客戶端的命令調用方法
* @author feng
*
*/
public class Invoker {
/**
* 命令對象
*/
public Command command;
/**
* 命令設置方法
* @param command
*/
public void setCommand(Command cmd){
this.command = cmd;
}
/**
* 命令執行方法
*/
public void execute(){
this.command.execute();
}
}
7、第七個文件TestMain.java
/**
* 測試Main方法
*/
public class TestMain {
public static void main(String args[]){
Document doc = new Document(); //文檔實體對象
AddCommand addCmd = new AddCommand(doc); //具體命令實體對象
UndoCommand undoCmd = new UndoCommand(doc); //具體命令實體對象
RedoCommand redoCmd = new RedoCommand(doc); //具體命令實體對象
Invoker invoker = new Invoker(); //調用者對象
invoker.setCommand(addCmd);
invoker.execute();
invoker.setCommand(addCmd);
invoker.execute();
invoker.setCommand(undoCmd);
invoker.execute();
invoker.setCommand(redoCmd);
invoker.execute();
}
雖然代碼看似挺多,但其實命令模式的結構還是比較清晰的,總的來說命令模式的使用流程就是首先創建一個抽象命令,然后創建多個具體命令實現抽象命令接口,然后創建一個命令接受者角色,它包含各種的行為的具體實現,然后再有一個命令調用者角色,提供給客戶端,用于接收客戶端的參數。
下面總結下命令模式的優點:
(1)命令模式將行為調用者和各種行為分隔開,降低程序的耦合,便于程序擴展。
(2)命令模式將行為的具體實現封裝起來,客戶端無需關心行為的具體實現。
(3)命令模式可為多種行為提供統一的調用入口,便于程序對行為的管理和控制。