Python 用一等函数重新审视“命令”设计模式
引言
在软件开发中,设计模式是解决常见问题的有效方法。“命令”设计模式旨在解耦调用操作的对象(调用者)和提供实现的对象(接收者)。本文将深入探讨“命令”模式,并介绍如何使用一等函数对其进行简化。
“命令”模式概述
模式目的
“命令”模式的核心目标是将调用操作的对象与实现操作的对象分离。在传统的实现中,会在调用者和接收者之间引入一个 Command 对象,该对象实现了只有一个方法(execute)的接口,通过调用接收者的方法来执行所需操作。这样做的好处是,调用者无需了解接收者的接口,不同的接收者可以适配不同的 Command 子类。
示例场景
以菜单驱动的文本编辑器为例,在《设计模式:可复用面向对象软件的基础》的示例中,调用者是图形应用程序中的菜单项,接收者是被编辑的文档或应用程序自身。像 PasteCommand 的接收者是 Document,OpenCommand 的接收者是应用程序。
UML 类图
图 6 - 2 展示了菜单驱动的文本编辑器使用“命令”设计模式的 UML 类图,其中 MacroCommand 可能保存一系列命令,其 execute() 方法会依次调用各个命令的相同方法。
用一等函数简化“命令”模式
函数替代 Command 实例
我们可以不向调用者提供 Command 实例,而是提供一个函数。此时,调用者直接调用 command() 即可,而无需调用 command.execute() 。
MacroCommand 的实现
MacroCommand 可以实现为定义了 call 方法的类,这样其实例就是可调用对象,各自维护着一个函数列表供以后调用。示例代码如下:
class MacroCommand: """一个执行一组命令的命令""" def __init__(self, commands): self.commands = list(commands) # 构建命令列表,确保参数可迭代并保存副本 def __call__(self): for command in self.commands: # 调用实例时,依次执行命令 command()
Python 提供的替代品
可调用实例
像示例中的 MacroCommand 这样的可调用实例,可以保存任何所需的状态,并且除了 call 方法之外,还可以提供其他方法。
闭包
可以使用闭包在调用之间保存函数的内部状态。
与“策略”模式的相似性
从更高的层面看,使用一等函数重新审视“命令”模式的方式与“策略”模式类似,都是把实现单方法接口的类的实例替换成可调用对象。因为每个 Python 可调用对象都实现了单方法接口 call。
总结
虽然复杂的“命令”模式(如支持撤销操作)可能需要更多的实现,但使用一等函数可以为其提供简化的解决方案。通过函数替代 Command 实例以及利用 Python 的可调用实例和闭包特性,我们可以在一定程度上简化“命令”模式的实现,提高代码的灵活性和可维护性。