一、说明
命令模式是一种行为设计模式,旨在对命令的封装,根据不同的请求将方法参数化、延迟请求执行或将其放入队列中,且能实现可撤销操作。
(一) 解决问题
- 将请求发送者和接受者解耦,请求发送者只需知道如何发送请求,而无需知道请求是如何被处理、谁来处理请求。
- 支持请求的排队、记录请求日志、撤销操作等功能。
(二) 使用场景
- 需要将操作参数化,以便在不同的时刻执行、排队或记录请求。
- 需要支持命令的撤销(Undo)操作。
- 需要支持命令的排队执行。
二、结构
- **发送者(Sender)**负责对请求进行初始化,其中必须包含一个成员变量来存储对于命令对象的引用。发送者触发命令,而不向接收者直接发送请求。注意,发送者并不负责创建命令对象:它通常会通过构造函数从客户端处获得预先生成的命令。
- **命令(Command)**接口通常仅声明一个执行命令的方法。
- **具体命令(ConcreteCommands)**会实现各种类型的请求。具体命令自身并不完成工作,而是会将调用委派给一个业务逻辑对象。但为了简化代码,这些类可以进行合并。接收对象执行方法所需的参数可以声明为具体命令的成员变量。你可以将命令对象设为不可变,仅允许通过构造函数对这些成员变量进行初始化。
- **接收者(Receiver)**类包含部分业务逻辑。几乎任何对象都可以作为接收者。绝大部分命令只处理如何将请求传递到接收者的细节,接收者自己会完成实际的工作。
- **客户端(Client)**会创建并配置具体命令对象。客户端必须将包括接收者实体在内的所有请求参数传递给命令的构造函数。此后,生成的命令就可以与一个或多个发送者相关联了。
三、伪代码
python
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
__doc__ = """
命令模式
例:模拟灯光控制场景,使用命令模式实现打开、关闭、撤销操作
"""
from abc import ABC, abstractmethod
from collections import deque
class Command(ABC):
"""抽象命令基类"""
@abstractmethod
def execute(self):
pass
@abstractmethod
def undo(self):
pass
class LightOnCommand(Command):
"""具体命令类(开灯)"""
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_on()
def undo(self):
self.light.turn_off()
class LightOffCommand(Command):
"""具体命令类(关灯)"""
def __init__(self, light):
self.light = light
def execute(self):
self.light.turn_off()
def undo(self):
self.light.turn_on()
class Light:
"""接收者类"""
def turn_on(self):
print(" - 灯光打开")
def turn_off(self):
print(" - 灯光关闭")
class RemoteControl:
"""调用者类"""
def __init__(self):
self.commands = {}
self.command_queue = deque()
self.undo_command = None
def set_command(self, slot, command):
self.commands[slot] = command
def press_button(self, slot):
if slot in self.commands:
self.commands[slot].execute()
self.undo_command = self.commands[slot]
def undo_last_command(self):
if self.undo_command:
self.undo_command.undo()
def run_commands(self):
while self.command_queue:
command = self.command_queue.popleft()
command.execute()
def add_to_queue(self, slot):
if slot in self.commands:
self.command_queue.append(self.commands[slot])
if __name__ == "__main__":
"""
执行命令
- 灯光打开
- 灯光关闭
撤销命令
- 灯光打开
排队执行命令
- 灯光关闭
- 灯光打开
"""
light = Light()
remote_control = RemoteControl()
remote_control.set_command(0, LightOnCommand(light))
remote_control.set_command(1, LightOffCommand(light))
print("执行命令")
remote_control.press_button(0)
remote_control.press_button(1)
print("撤销命令")
remote_control.undo_last_command()
print("排队执行命令")
remote_control.add_to_queue(1)
remote_control.add_to_queue(0)
remote_control.run_commands()
四、优缺点
优点
- **降低系统耦合度:**命令模式将请求发送者和接收者解耦,发送者和接收者之间不直接交互,降低了彼此之间的依赖关系,使得系统更加灵活。
- **容易扩展:**新的命令类可以很容易地添加到系统中,而不影响其他类。
- **支持撤销和重做:**命令模式可以将命令对象保存起来,以支持撤销和重做操作。
- **支持命令的排队和记录:**可以将命令对象排队起来,实现对请求的延迟执行或记录日志。
缺点
- 增加系统复杂度:每个命令都需要一个具体命令类,可能会导致类的数量增加,增加系统的复杂度。