介紹
說到命令模式,我們可以聯想到上級下達命令,下級接收命令去執行,遙控器發送命令,相應的機器做出反應。就比如電燈泡的開關,排氣扇的開關等等。這些開關就是發送命令的對象,而電燈泡和排氣扇就是接受命令的對象,如下圖。
命令模式(Command Pattern)是一種數據驅動的設計模式,它屬于行為型模式。請求以命令的形式包裹在對象中,并傳給調用對象。調用對象尋找可以處理該命令的合適的對象,并把該命令傳給相應的對象,該對象執行命令。命令模式可以對發送者和接收者完全解耦,發送者與接收者之間沒有直接引用關系,發送請求的對象只需要知道如何發送請求,而不必知道如何完成請求。這就是命令模式的模式動機。
角色
● Command(抽象命令類):抽象命令類一般是一個抽象類或接口,在其中聲明了用于執行請求的execute()等方法,通過這些方法可以調用請求接收者的相關操作。
● ConcreteCommand(具體命令類):具體命令類是抽象命令類的子類,實現了在抽象命令類中聲明的方法,它對應具體的接收者對象,將接收者對象的動作綁定其中。在實現execute()方法時,將調用接收者對象的相關操作(Action)。
● Invoker(調用者):調用者即請求發送者,它通過命令對象來執行請求。一個調用者并不需要在設計時確定其接收者,因此它只與抽象命令類之間存在關聯關系。在程序運行時可以將一個具體命令對象注入其中,再調用具體命令對象的execute()方法,從而實現間接調用請求接收者的相關操作。
● Receiver(接收者):接收者執行與請求相關的操作,它具體實現對請求的業務處理。
結構圖
時序圖
案例
這里就用電燈的開關作為案例
接收者接口
public interface Receiver {
void action();
}
電燈接收者類
有個flag表示電燈狀態是否是開啟還是關閉
public class LightReceiver implements Receiver{
private boolean flag = false;
@Override
public void action() {
if (flag) {
System.out.println("燈現在是開著的");
} else {
System.out.println("燈已經關了");
}
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
命令接口
public interface Command {
void execute();
}
電燈命令類
public class LightCommand implements Command{
private LightReceiver lightReceiver;
public LightCommand(LightReceiver lightReceiver) {
super();
this.lightReceiver = lightReceiver;
}
@Override
public void execute() {
boolean flag = lightReceiver.isFlag() ? false : true;
lightReceiver.setFlag(flag);
lightReceiver.action();
}
}
開關類
public class SwitchInvoker {
private Command command;
public SwitchInvoker(Command command) {
this.command = command;
}
public void executeCommand(){
command.execute();
}
}
測試類
public class Client {
public static void main(String[] args) {
Command command = new LightCommand(new LightReceiver());
SwitchInvoker invoker = new SwitchInvoker(command);
for (int i = 0; i < 6; i++) {
invoker.executeCommand();
}
}
}
測試結果
總結
--
使用命令模式可以降低了系統耦合度,也比較容易擴展,但是也可能會導致某些系統有過多的具體命令類。
在碰到需要對行為進行"記錄、撤銷/重做、事務"等處理時,或者系統需要將請求調用者和請求接收者解耦,使得調用者和接收者不直接交互,又或者系統需要在不同的時間指定請求、請求排隊和執行請求時就可以使用命令模式。