介紹
說到命令模式,我們可以聯(lián)想到上級下達(dá)命令,下級接收命令去執(zhí)行,遙控器發(fā)送命令,相應(yīng)的機(jī)器做出反應(yīng)。就比如電燈泡的開關(guān),排氣扇的開關(guān)等等。這些開關(guān)就是發(fā)送命令的對象,而電燈泡和排氣扇就是接受命令的對象,如下圖。
命令模式(Command Pattern)是一種數(shù)據(jù)驅(qū)動的設(shè)計模式,它屬于行為型模式。請求以命令的形式包裹在對象中,并傳給調(diào)用對象。調(diào)用對象尋找可以處理該命令的合適的對象,并把該命令傳給相應(yīng)的對象,該對象執(zhí)行命令。命令模式可以對發(fā)送者和接收者完全解耦,發(fā)送者與接收者之間沒有直接引用關(guān)系,發(fā)送請求的對象只需要知道如何發(fā)送請求,而不必知道如何完成請求。這就是命令模式的模式動機(jī)。
角色
● Command(抽象命令類):抽象命令類一般是一個抽象類或接口,在其中聲明了用于執(zhí)行請求的execute()等方法,通過這些方法可以調(diào)用請求接收者的相關(guān)操作。
● ConcreteCommand(具體命令類):具體命令類是抽象命令類的子類,實(shí)現(xiàn)了在抽象命令類中聲明的方法,它對應(yīng)具體的接收者對象,將接收者對象的動作綁定其中。在實(shí)現(xiàn)execute()方法時,將調(diào)用接收者對象的相關(guān)操作(Action)。
● Invoker(調(diào)用者):調(diào)用者即請求發(fā)送者,它通過命令對象來執(zhí)行請求。一個調(diào)用者并不需要在設(shè)計時確定其接收者,因此它只與抽象命令類之間存在關(guān)聯(lián)關(guān)系。在程序運(yùn)行時可以將一個具體命令對象注入其中,再調(diào)用具體命令對象的execute()方法,從而實(shí)現(xiàn)間接調(diào)用請求接收者的相關(guān)操作。
● Receiver(接收者):接收者執(zhí)行與請求相關(guān)的操作,它具體實(shí)現(xiàn)對請求的業(yè)務(wù)處理。
結(jié)構(gòu)圖
時序圖
案例
這里就用電燈的開關(guān)作為案例
接收者接口
public interface Receiver {
void action();
}
電燈接收者類
有個flag表示電燈狀態(tài)是否是開啟還是關(guān)閉
public class LightReceiver implements Receiver{
private boolean flag = false;
@Override
public void action() {
if (flag) {
System.out.println("燈現(xiàn)在是開著的");
} else {
System.out.println("燈已經(jīng)關(guān)了");
}
}
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();
}
}
開關(guān)類
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();
}
}
}
測試結(jié)果
總結(jié)
--
使用命令模式可以降低了系統(tǒng)耦合度,也比較容易擴(kuò)展,但是也可能會導(dǎo)致某些系統(tǒng)有過多的具體命令類。
在碰到需要對行為進(jìn)行"記錄、撤銷/重做、事務(wù)"等處理時,或者系統(tǒng)需要將請求調(diào)用者和請求接收者解耦,使得調(diào)用者和接收者不直接交互,又或者系統(tǒng)需要在不同的時間指定請求、請求排隊和執(zhí)行請求時就可以使用命令模式。