命令模式將「請求」封裝為物件,使客戶端能以不同請求參數化、支援佇列、日誌、撤銷/重做。本文透過「電視遙控器」經典案例,完整展示五大角色結構、程式碼實作、執行結果與優缺點分析,並探討何時該引入模式、何時該保持簡單。
execute()。execute()。Tv.turnOn())。// Command 介面
interface Command { void execute(); }
// Receiver:電視機
class Tv {
int channel = 0;
void turnOn() { System.out.println("The television is on."); }
void turnOff() { System.out.println("The television is off."); }
void changeChannel(int c) { channel = c; System.out.println("Now TV channel is " + c); }
}
// ConcreteCommands
class CommandOn implements Command {
private final Tv tv;
CommandOn(Tv t) { tv = t; }
public void execute() { tv.turnOn(); }
}
class CommandOff implements Command {
private final Tv tv;
CommandOff(Tv t) { tv = t; }
public void execute() { tv.turnOff(); }
}
class CommandChange implements Command {
private final Tv tv; private final int channel;
CommandChange(Tv t, int c) { tv = t; channel = c; }
public void execute() { tv.changeChannel(channel); }
}
// Invoker:遙控器
class Control {
private final Command onCmd, offCmd, chgCmd;
Control(Command on, Command off, Command chg) { onCmd=on; offCmd=off; chgCmd=chg; }
void turnOn() { onCmd.execute(); }
void turnOff() { offCmd.execute(); }
void changeChannel() { chgCmd.execute(); }
}
// Client 組裝測試
public class Client {
public static void main(String[] args) {
Tv tv = new Tv();
Control ctrl = new Control(new CommandOn(tv), new CommandOff(tv), new CommandChange(tv, 2));
ctrl.turnOn(); ctrl.changeChannel(); ctrl.turnOff();
}
}
The television is on.
Now TV channel is 2
The television is off.
| 優點 | 缺點 |
|---|---|
| 封裝性佳,客戶端不需知曉執行細節 | 命令類過多時類別爆炸,維護成本高 |
| 擴充性強,新增命令只需新增類別 | 簡單邏輯引入模式屬於過度設計 |
| 支援佇列、日誌、Undo/Redo 進階功能 | 間接層增加閱讀難度 |
switch-case 或方法封裝已足夠,不要為了用模式而用模式——遵循 YAGNI 原則,重構時再引入。