设计模式实战:命令模式(Command)

在很多系统中,你会遇到这样的需求:

  • 把"操作"当成对象传递
  • 支持操作的撤销(Undo)
  • 支持操作队列 / 延迟执行
  • 支持日志记录与重放

例如:

  • 编辑器的撤销/重做
  • 任务队列(异步执行)
  • 按钮点击绑定不同行为
  • 审批操作记录

如果直接写函数调用:

python 复制代码
light.turn_on()
light.turn_off()

看起来简单,但问题是:

  • 操作无法记录
  • 无法撤销
  • 无法统一调度

这时候就需要 ------ 命令模式(Command)。


一、命令模式解决什么问题?

一句话:

将请求封装为对象,从而使你可以用不同的请求对客户进行参数化。

关键词:

  • 请求封装
  • 解耦调用者与执行者
  • 支持撤销/重做
  • 支持队列

二、核心角色

命令模式包含四个角色:

1️⃣ Command(命令接口)

定义执行操作的接口。

2️⃣ ConcreteCommand(具体命令)

实现具体操作,绑定接收者。

3️⃣ Receiver(接收者)

真正执行动作的对象。

4️⃣ Invoker(调用者)

触发命令执行。

结构:

复制代码
Invoker → Command → Receiver

三、一个典型场景:智能家居控制

我们用"控制灯"作为例子。


四、Python 实现命令模式

1️⃣ 接收者(Receiver)

python 复制代码
class Light:

    def turn_on(self):
        print("灯打开")

    def turn_off(self):
        print("灯关闭")

2️⃣ 命令接口

python 复制代码
from abc import ABC, abstractmethod

class Command(ABC):

    @abstractmethod
    def execute(self):
        pass

3️⃣ 具体命令

python 复制代码
class TurnOnCommand(Command):

    def __init__(self, light: Light):
        self.light = light

    def execute(self):
        self.light.turn_on()


class TurnOffCommand(Command):

    def __init__(self, light: Light):
        self.light = light

    def execute(self):
        self.light.turn_off()

4️⃣ 调用者(Invoker)

python 复制代码
class RemoteControl:

    def __init__(self):
        self.command = None

    def set_command(self, command: Command):
        self.command = command

    def press_button(self):
        self.command.execute()

5️⃣ 使用方式

python 复制代码
light = Light()

on_command = TurnOnCommand(light)
off_command = TurnOffCommand(light)

remote = RemoteControl()

remote.set_command(on_command)
remote.press_button()

remote.set_command(off_command)
remote.press_button()

输出:

复制代码
灯打开
灯关闭

五、命令模式的核心价值

命令模式本质是:

把"操作"变成对象。

这样带来的好处:

  • 操作可以存储
  • 操作可以传递
  • 操作可以组合
  • 操作可以撤销

六、实现撤销(Undo)

命令模式一个重要能力:撤销操作。

修改命令接口:

python 复制代码
class Command(ABC):

    @abstractmethod
    def execute(self):
        pass

    @abstractmethod
    def undo(self):
        pass

实现:

python 复制代码
class TurnOnCommand(Command):

    def __init__(self, light):
        self.light = light

    def execute(self):
        self.light.turn_on()

    def undo(self):
        self.light.turn_off()

Invoker 记录历史:

python 复制代码
class RemoteControl:

    def __init__(self):
        self.history = []

    def execute(self, command):
        command.execute()
        self.history.append(command)

    def undo(self):
        if self.history:
            command = self.history.pop()
            command.undo()

使用:

python 复制代码
remote = RemoteControl()

cmd = TurnOnCommand(light)

remote.execute(cmd)
remote.undo()

七、命令模式 vs 策略模式

很多人会混淆。

区别很关键:

对比点 命令模式 策略模式
关注点 请求封装 算法替换
是否记录操作 是 否
是否支持撤销 是 否

一句话:

策略是"怎么做",

命令是"做什么"。


八、命令模式 vs 观察者模式

对比点 命令模式 观察者模式
调用方式 主动触发 被动通知
关系 一对一 一对多

一句话:

命令是"我让你做",

观察者是"发生了你自己处理"。


九、真实项目中的应用

非常常见:

1️⃣ 任务队列

例如:

  • Celery
  • 异步任务系统

每个任务本质就是一个命令。


2️⃣ 撤销/重做系统

例如:

  • 文本编辑器
  • 图形编辑器

3️⃣ 审计日志

记录用户操作:

python 复制代码
delete_user(1001)

可以记录为命令对象,后续回放。


4️⃣ UI 按钮绑定

按钮:

python 复制代码
button.onClick = command.execute

十、更 Pythonic 的写法(函数版)

Python 中可以不用类。

直接用函数:

python 复制代码
def turn_on():
    print("灯打开")

def turn_off():
    print("灯关闭")

Invoker:

python 复制代码
class Remote:

    def __init__(self):
        self.commands = []

    def execute(self, cmd):
        cmd()
        self.commands.append(cmd)

简单直接。


十一、优缺点

✅ 优点

  • 解耦调用者与执行者
  • 支持撤销/重做
  • 支持队列、日志
  • 灵活扩展

❌ 缺点

  • 类数量增加
  • 简单场景可能过度设计

十二、什么时候使用命令模式?

适合:

  • 需要记录操作
  • 需要撤销/重做
  • 需要队列执行
  • 操作需要解耦

不适合:

  • 简单函数调用
  • 无需扩展

十三、一句话总结

命令模式的本质是:
把"操作"变成对象,从而实现可记录、可撤销、可扩展。

换句话说:

不要直接调用方法,把调用封装起来。


相关推荐
XCDoris1 小时前
郴州logo设计机构
大数据·人工智能·python
gCode Teacher 格码致知1 小时前
Pandas教学-17:Series与Dataframe的关系
开发语言·python·pandas
马良神笔2 小时前
2026 年Rag最近技术前沿总结
后端·python·django
不像程序员的程序媛3 小时前
maven基础
python·pycharm·maven
xiaogai_gai4 小时前
仅查询策略实战:从金蝶云·星空旗舰版定时拉取收料通知单
大数据·数据库·python
benchmark_cc4 小时前
Python 量化系统如何设计统一的数据访问接口:从策略解耦到数据层架构
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
高晶4 小时前
无乘法器实现LC二阶滤波器:基于移位运算的快速算法与四种精度推导
算法·设计模式·程序员
const_qiu5 小时前
第四章 00:开篇 —— 从「会聊天」到「记得住、会干活、能协作」
java·开发语言·人工智能·python
高晶5 小时前
主从自动分配算法:平均值乘以设备数一半的选举基准值解析
算法·设计模式·程序员
延晗5 小时前
【从零开始 DeepSeek Harness 插件开发教程】二、一切皆插件:简单理解一下 Cordis 内核与 DSH 心智模型
设计模式·deepseek