命令模式
High Contrast
Dark Mode
Light Mode
Sepia
Forest
2 min read428 words

命令模式

命令模式(Command Pattern)将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

问题定义

场景1:智能家居控制

# ❌ 问题:紧密耦合
class SmartHome:
"""智能家居控制器"""
def turn_on_light(self):
print("开灯")
def turn_off_light(self):
print("关灯")
def open_curtains(self):
print("开窗帘")
def close_curtains(self):
print("关窗帘")
def turn_on_ac(self):
print("开空调")
def turn_off_ac(self):
print("关空调")
# 问题:每个设备都需要单独的方法,无法参数化
# 想要批量执行、撤销操作很难实现

场景2:文本编辑器

# ❌ 问题:无法撤销
class TextEditor:
"""文本编辑器"""
def __init__(self):
self.text = ""
def type(self, chars):
self.text += chars
print(f"输入: {chars}")
def delete(self, count):
self.text = self.text[:-count]
print(f"删除{count}个字符")
# 问题:无法撤销操作
# 想要实现撤销需要复杂的逻辑

解决方案

命令模式将请求封装成对象,从而可以使用不同的请求对客户进行参数化。

classDiagram class Command { <> +execute() +undo() } class ConcreteCommand { -receiver: Receiver +execute() +undo() } class Invoker { -command: Command +setCommand() +executeCommand() +undoCommand() } class Receiver { +action() } class Client { +createCommand() } Command <|-- ConcreteCommand Invoker o-- Command : uses ConcreteCommand o-- Receiver : uses Client ..> ConcreteCommand : creates

标准实现

命令接口

from abc import ABC, abstractmethod
class Command(ABC):
"""命令接口"""
@abstractmethod
def execute(self):
pass
@abstractmethod
def undo(self):
pass

接收者

class Light:
"""电灯 - 接收者"""
def on(self):
print("💡 开灯")
def off(self):
print("🌙 关灯")
class AC:
"""空调 - 接收者"""
def on(self):
print("❄️ 开空调")
def off(self):
print("🔥 关空调")

具体命令

class LightOnCommand(Command):
"""开灯命令"""
def __init__(self, light):
self._light = light
def execute(self):
self._light.on()
def undo(self):
self._light.off()
class LightOffCommand(Command):
"""关灯命令"""
def __init__(self, light):
self._light = light
def execute(self):
self._light.off()
def undo(self):
self._light.on()
class ACOnCommand(Command):
"""开空调命令"""
def __init__(self, ac):
self._ac = ac
def execute(self):
self._ac.on()
def undo(self):
self._ac.off()
class ACOffCommand(Command):
"""关空调命令"""
def __init__(self, ac):
self._ac = ac
def execute(self):
self._ac.off()
def undo(self):
self._ac.on()

调用者

class RemoteControl:
"""遥控器 - 调用者"""
def __init__(self):
self._command = None
self._undo_command = None
def set_command(self, command: Command):
"""设置命令"""
self._command = command
def press_button(self):
"""按下按钮"""
if self._command:
self._undo_command = self._command
self._command.execute()
def press_undo(self):
"""按下撤销按钮"""
if self._undo_command:
self._undo_command.undo()

客户端使用

# 创建接收者
living_room_light = Light()
bedroom_ac = AC()
# 创建命令
light_on = LightOnCommand(living_room_light)
light_off = LightOffCommand(living_room_light)
ac_on = ACOnCommand(bedroom_ac)
ac_off = ACOffCommand(bedroom_ac)
# 创建调用者
remote = RemoteControl()
# 执行命令
print("开灯:")
remote.set_command(light_on)
remote.press_button()
print("\n开空调:")
remote.set_command(ac_on)
remote.press_button()
print("\n撤销操作:")
remote.press_undo()
print("\n关灯:")
remote.set_command(light_off)
remote.press_button()

实战应用

应用1:智能家居系统

from abc import ABC, abstractmethod
class Command(ABC):
@abstractmethod
def execute(self):
pass
@abstractmethod
def undo(self):
pass
class SmartHomeController:
"""智能家居控制器 - 接收者"""
def turn_on_light(self, room):
print(f"💡 打开{room}的灯")
def turn_off_light(self, room):
print(f"🌙 关闭{room}的灯")
def open_curtains(self, room):
print(f"🪟 打开{room}的窗帘")
def close_curtains(self, room):
print(f"🪟 关闭{room}的窗帘")
def set_temperature(self, temp):
print(f"🌡️ 设置空调温度: {temp}°C")
# 具体命令
class LightOnCommand(Command):
def __init__(self, controller, room):
self._controller = controller
self._room = room
def execute(self):
self._controller.turn_on_light(self._room)
def undo(self):
self._controller.turn_off_light(self._room)
class CurtainsOpenCommand(Command):
def __init__(self, controller, room):
self._controller = controller
self._room = room
def execute(self):
self._controller.open_curtains(self._room)
def undo(self):
self._controller.close_curtains(self._room)
class SetTemperatureCommand(Command):
def __init__(self, controller, temp):
self._controller = controller
self._temp = temp
self._prev_temp = 25  # 默认温度
def execute(self):
self._prev_temp = 24  # 假设当前是24度
self._controller.set_temperature(self._temp)
def undo(self):
self._controller.set_temperature(self._prev_temp)
# 宏命令 - 执行多个命令
class MacroCommand(Command):
"""宏命令"""
def __init__(self, commands):
self._commands = commands
def execute(self):
for command in self._commands:
command.execute()
def undo(self):
# 反向撤销
for command in reversed(self._commands):
command.undo()
# 调用者
class VoiceControl:
"""语音控制器 - 调用者"""
def __init__(self):
self._commands = {}
self._history = []
def add_command(self, name, command):
"""添加语音指令"""
self._commands[name] = command
def execute_voice_command(self, command_name):
"""执行语音指令"""
if command_name in self._commands:
command = self._commands[command_name]
self._history.append(command)
print(f"🎤 语音指令: '{command_name}'")
command.execute()
return True
return False
def undo_last(self):
"""撤销上一个指令"""
if self._history:
command = self._history.pop()
print("🔄 撤销操作")
command.undo()
# 使用
controller = SmartHomeController()
# 创建命令
light_on = LightOnCommand(controller, "客厅")
curtains_open = CurtainsOpenCommand(controller, "客厅")
set_temp = SetTemperatureCommand(controller, 26)
# 创建回家场景宏命令
come_home = MacroCommand([light_on, curtains_open, set_temp])
# 创建语音控制器
voice = VoiceControl()
voice.add_command("回家", come_home)
voice.add_command("开灯", light_on)
voice.add_command("开窗帘", curtains_open)
# 执行语音指令
voice.execute_voice_command("回家")
voice.execute_voice_command("开灯")
print("\n撤销操作:")
voice.undo_last()

应用2:文本编辑器

from abc import ABC, abstractmethod
class Command(ABC):
@abstractmethod
def execute(self):
pass
@abstractmethod
def undo(self):
pass
class TextEditor:
"""文本编辑器 - 接收者"""
def __init__(self):
self.text = ""
self.cursor = 0
def insert(self, chars, position):
"""插入文本"""
self.text = self.text[:position] + chars + self.text[position:]
self.cursor = position + len(chars)
print(f"插入文本: '{chars}'")
def delete(self, start, end):
"""删除文本"""
deleted = self.text[start:end]
self.text = self.text[:start] + self.text[end:]
print(f"删除文本: '{deleted}'")
def copy(self, start, end):
"""复制文本"""
return self.text[start:end]
def paste(self, text, position):
"""粘贴文本"""
self.insert(text, position)
def get_text(self):
"""获取文本"""
return self.text
# 具体命令
class InsertCommand(Command):
def __init__(self, editor, text, position=None):
self._editor = editor
self._text = text
self._position = position if position is not None else editor.cursor
def execute(self):
self._editor.insert(self._text, self._position)
def undo(self):
start = self._position
end = self._position + len(self._text)
self._editor.delete(start, end)
class DeleteCommand(Command):
def __init__(self, editor, start, end):
self._editor = editor
self._start = start
self._end = end
self._deleted_text = ""
def execute(self):
self._deleted_text = self._editor.copy(self._start, self._end)
self._editor.delete(self._start, self._end)
def undo(self):
self._editor.paste(self._deleted_text, self._start)
class CutCommand(Command):
def __init__(self, editor, start, end):
self._editor = editor
self._start = start
self._end = end
self._cut_text = ""
def execute(self):
self._cut_text = self._editor.copy(self._start, self._end)
self._editor.delete(self._start, self._end)
print(f"剪切文本: '{self._cut_text}'")
def undo(self):
self._editor.paste(self._cut_text, self._start)
# 调用者
class EditorApp:
"""编辑器应用 - 调用者"""
def __init__(self, editor):
self._editor = editor
self._history = []
self._current_position = 0
def insert(self, text):
command = InsertCommand(self._editor, text)
self._execute(command)
def delete(self, count):
start = self._editor.cursor - count
end = self._editor.cursor
command = DeleteCommand(self._editor, start, end)
self._execute(command)
def cut(self, start, end):
command = CutCommand(self._editor, start, end)
self._execute(command)
def undo(self):
if self._current_position > 0:
self._current_position -= 1
command = self._history[self._current_position]
command.undo()
print("撤销操作")
else:
print("没有可撤销的操作")
def redo(self):
if self._current_position < len(self._history):
command = self._history[self._current_position]
command.execute()
self._current_position += 1
print("重做操作")
def _execute(self, command):
# 如果在历史中间执行新命令,删除后续历史
if self._current_position < len(self._history):
self._history = self._history[:self._current_position]
command.execute()
self._history.append(command)
self._current_position += 1
def show_text(self):
print(f"\n当前文本: '{self._editor.get_text()}'")
# 使用
editor = TextEditor()
app = EditorApp(editor)
app.insert("Hello ")
app.insert("World!")
app.show_text()
# 当前文本: 'Hello World!'
app.delete(1)
app.show_text()
# 当前文本: 'Hello World'
app.undo()
app.show_text()
# 当前文本: 'Hello World!'
app.redo()
app.show_text()
# 当前文本: 'Hello World'

应用3:队列和延迟执行

from abc import ABC, abstractmethod
from queue import Queue
from threading import Thread
import time
class Command(ABC):
@abstractmethod
def execute(self):
pass
class Task:
"""任务 - 接收者"""
def __init__(self, name):
self.name = name
def run(self):
print(f"执行任务: {self.name}")
class TaskCommand(Command):
"""任务命令"""
def __init__(self, task):
self._task = task
def execute(self):
self._task.run()
class CommandQueue:
"""命令队列 - 调用者"""
def __init__(self):
self._queue = Queue()
self._running = False
self._worker_thread = None
def add_command(self, command):
"""添加命令到队列"""
self._queue.put(command)
print(f"📥 命令已加入队列,队列长度: {self._queue.qsize()}")
def start(self):
"""启动工作线程"""
if not self._running:
self._running = True
self._worker_thread = Thread(target=self._process_commands)
self._worker_thread.start()
print("🚀 命令队列已启动")
def stop(self):
"""停止工作线程"""
self._running = False
if self._worker_thread:
self._worker_thread.join()
print("🛑 命令队列已停止")
def _process_commands(self):
"""处理队列中的命令"""
while self._running:
try:
command = self._queue.get(timeout=1)
print("📤 从队列获取命令")
command.execute()
self._queue.task_done()
time.sleep(1)  # 模拟执行时间
except:
pass
class DelayedCommandExecutor:
"""延迟命令执行器"""
def __init__(self):
self._scheduled_commands = []
def schedule(self, command, delay_seconds):
"""延迟执行命令"""
import threading
def delayed_execute():
time.sleep(delay_seconds)
print(f"⏰ 延迟{delay_seconds}秒后执行:")
command.execute()
thread = Thread(target=delayed_execute)
thread.start()
print(f"⏳ 命令已安排在{delay_seconds}秒后执行")
# 使用
# 创建命令队列
queue = CommandQueue()
queue.start()
# 添加多个命令到队列
queue.add_command(TaskCommand(Task("任务1")))
queue.add_command(TaskCommand(Task("任务2")))
queue.add_command(TaskCommand(Task("任务3")))
queue.add_command(TaskCommand(Task("任务4")))
# 等待队列处理
time.sleep(6)
queue.stop()
# 延迟执行
print("\n延迟执行示例:")
executor = DelayedCommandExecutor()
executor.schedule(TaskCommand(Task("延迟任务1")), 2)
executor.schedule(TaskCommand(Task("延迟任务2")), 4)
time.sleep(6)

优缺点

✅ 优点

优点 说明
解耦 发送者和接收者解耦
可扩展 新增命令无需修改代码
可撤销 支持撤销操作
可组合 可组合成宏命令
延迟执行 支持队列和延迟执行

❌ 缺点

缺点 说明
类数量多 每个命令一个类
复杂度 简单操作可能过度设计
内存 命令对象占用内存

适用场景

场景 是否适合
需要撤销操作 ✅ 适合
需要批量执行 ✅ 适合
需要延迟执行 ✅ 适合
需要记录日志 ✅ 适合
简单直接调用 ❌ 不适合

本章要点


下一步迭代器模式 🚀