設計模式-15命令模式(Command Pattern)
- 2020 年 3 月 13 日
- 筆記
1.模式動機
在軟件設計中,我們經常需要向某些對象發送請求,但是並不知道請求的接收者是誰,也不知道被請求的操作是哪個,我們只需在程序運行時指定具體的請求接收者即可,此時,可以使用命令模式來進行設計,使得請求發送者與請求接收者消除彼此之間的耦合,讓對象之間的調用關係更加靈活。
命令模式可以對發送者和接收者完全解耦,發送者與接收者之間沒有直接引用關係,發送請求的對象只需要知道如何發送請求,而不必知道如何完成請求。這就是命令模式的模式動機。
2.模式定義
命令模式(Command Pattern):將一個請求封裝為一個對象,從而使我們可用不同的請求對客戶進行參數化;對請求排隊或者記錄請求日誌,以及支持可撤銷的操作。
命令模式是一種對象行為型模式,其別名為動作(Action)模式或事務(Transaction)模式。
3.模式結構
- 抽象命令類(Command):聲明執行命令的接口,擁有執行命令的抽象方法 execute()。
- 具體命令角色(Concrete Command):是抽象命令類的具體實現類,它擁有接收者對象,並通過調用接收者的功能來完成命令要執行的操作。
- 實現者/接收者(Receiver):執行命令功能的相關操作,是具體命令對象業務的真正實現者。
- 調用者/請求者(Invoker):是請求的發送者,它通常擁有很多的命令對象,並通過訪問命令對象來執行相關請求,它不直接訪問接收者。
具體調用順序為 Client => Invoker => Concreate Command => Receiver。
Invoker 並不直接調用 Receiver,而是通過具體命令對象來調用實現者。
4.模式代碼
# 實現者/接受者 public class Receiver { public void action() { System.out.println("接受者的 Action 方法"); } } # 抽象命令類 public abstract class Command { public abstract void execute(); } # 具體命令類,內部 new 了一個實現者的對象 public class ConcreteCommand extends Command { private Receiver receiver; public ConcreteCommand() { this.receiver = new Receiver(); } @Override public void execute() { receiver.action(); } } # 調用者/請求者,通過賦予不同的 command 值來調用不同的的 command public class Invoker { private Command command; public Invoker(Command command) { this.command = command; } public void setCommand(Command command) { this.command = command; } public void call() { System.out.println("call 執行命令 Command"); command.execute(); } } # Client public class Client { public static void main(String[] args) { Command cmd = new ConcreteCommand(); Invoker invoker = new Invoker(cmd); invoker.call(); } }
首先把它們的調用關係理清楚了就明白這個模式了。
5.總結
分析
命令模式的本質是對命令進行封裝,將發出命令的責任和執行命令的責任分割開。
- 每一個命令都是一個操作:請求的一方發出請求,要求執行一個操作;接收的一方收到請求,並執行操作。
- 命令模式允許請求的一方和接收的一方獨立開來,使得請求的一方不必知道接收請求的一方的接口,更不必知道請求是怎麼被接收,以及操作是否被執行、何時被執行,以及是怎麼被執行的。
- 命令模式使請求本身成為一個對象,這個對象和其他對象一樣可以被存儲和傳遞。
- 命令模式的關鍵在於引入了抽象命令接口,且發送者針對抽象命令接口編程,只有實現了抽象命令接口的具體命令才能與接收者相關聯。
優點
- 降低系統的耦合度。
- 新的命令可以很容易地加入到系統中。
- 可以比較容易地設計一個命令隊列和宏命令(組合命令)。
- 可以方便地實現對請求的Undo和Redo。
缺點
- 使用命令模式可能會導致某些系統有過多的具體命令類。因為針對每一個命令都需要設計一個具體命令類,因此某些系統可能需要大量具體命令類,這將影響命令模式的使用。