簡介
命令模式(Command Pattern)是一種行為型設計模式,它將請求或操作封裝為獨立的對象,允許用户參數化客户端、隊列請求、記錄日誌,並支持撤銷操作。該模式的核心思想是將“請求的發起者”與“請求的執行者”解耦,使兩者通過命令對象進行交互。
角色組成:
- 調用者(Invoker),負責發起請求的類
- 命令(Command),一個接口,通常僅聲明一個執行命令的方法
- 具體命令(ConcretCommand),實現各種類型請求的類
- 接受者(Receiver),包含部分業務邏輯的接口或類。大部分命令只處理如何將請求傳遞給接受者的細節,接受者會完成實際的工作。
- 客户端(Client),創建並配置具體命令對象。
適用場景
- 解耦請求發起者與執行者:當需要將操作調用者(如UI控件)與具體實現(如業務邏輯)分離時。
- 支持撤銷/重做:如文本編輯器、圖形軟件中的操作歷史。
- 延遲執行或任務隊列:將命令存入隊列,按計劃或異步執行。
- 事務管理:將多個操作組合成原子事務,支持回滾。
- 宏命令(組合命令):批量執行一系列命令。
優點
- 解耦:調用者與接收者無需直接交互,降低耦合度。
- 擴展性:新增命令無需修改現有代碼,符合開閉原則。
- 支持複雜操作:可輕鬆實現撤銷、重做、事務、宏命令。
- 靈活調度:命令可排隊、延遲執行或記錄日誌。
缺點
- 類數量增加:每個命令需單獨類,可能導致代碼膨脹。
- 複雜度提升:對簡單操作可能過度設計,增加理解成本。
- 性能開銷:多層間接調用可能影響效率(通常可忽略)。
示例代碼
Go
package command
import "fmt"
// 命令 接口
type Command interface {
Execute()
}
// 調用者類
type Button struct {
Command Command
}
func (b *Button) Press() {
b.Command.Execute()
}
// 具體命令類
type OnCommand struct {
Device Device
}
func (c *OnCommand) Execute() {
c.Device.On()
}
// 具體命令類
type OffCommand struct {
Device Device
}
func (c *OffCommand) Execute() {
c.Device.Off()
}
// 接收者接口
type Device interface {
On()
Off()
}
// 具體接受者類
type Light struct {
isRunning bool
}
func (t *Light) On() {
t.isRunning = true
fmt.Println("Light is on")
}
func (t *Light) Off() {
t.isRunning = false
fmt.Println("Light is off")
}
客户端
package command
import "testing"
func TestCommand(t *testing.T) {
Light := &Light{}
onCommand := &OnCommand{
Device: Light,
}
OffCommand := &OffCommand{
Device: Light,
}
onButton := &Button{
Command: onCommand,
}
onButton.Press()
offButton := &Button{
Command: OffCommand,
}
offButton.Press()
}
Python
from abc import ABCMeta, abstractmethod
class Command(metaclass=ABCMeta):
@abstractmethod
def execute(self):
pass
class Device(metaclass=ABCMeta):
@abstractmethod
def on(self):
pass
@abstractmethod
def off(self):
pass
class Button:
def __init__(self, command: Command):
self.command = command
def press(self):
self.command.execute()
class OnCommand(Command):
def __init__(self, device: Device):
self.device = device
def execute(self):
self.device.on()
class OffCommand(Command):
def __init__(self, device: Device):
self.device = device
def execute(self):
self.device.off()
class Light(Device):
def __init__(self):
self.is_running = False
def on(self):
self.is_running = True
print("Light is on")
def off(self):
self.is_running = False
print("Light is off")
if __name__ == "__main__":
light = Light()
on_command = OnCommand(light)
off_command = OffCommand(light)
button = Button(on_command)
button.press()
button = Button(off_command)
button.press()