直接调用时执行方法的一般方式。然而,有时我们无法控制方法执行的时机与上下文。这种情况下,可以将方法封装在对象的内部。通过在对象内部存储调用方法所需要的信息,就可以让客户端或者服务决定何时调用该方法。
命令模式的意图是将请求封装在对象内部。
命令模式的结构
命令模式包含以下主要角色。
抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法 execute()。
具体命令角色(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
调用者/请求者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。
其结构图如图所示。
命令模式的实现
命令模式的代码如下:
调用者
1 | class Invoker |
抽象命令
1 | interface Command |
具体命令
1 | class ConcreteCommand implements Command |
接收者
1 | class Receiver |
运行
1 | public static void main(String[] args) |
结果
客户访问调用者的call()方法...
调用者执行命令command...
接收者的action()方法被调用...
常见案例及应用场景
常见案例:struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的 Command。
应用场景:
- 当系统需要将请求调用者与请求接收者解耦时,命令模式使得调用者和接收者不直接交互。
- 当系统需要随机请求命令或经常增加或删除命令时,命令模式比较方便实现这些功能。
- 当系统需要执行一组操作时,命令模式可以定义宏命令来实现该功能。
- 当系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作时,可以将命令对象存储起来,采用备忘录模式来实现。
总结
命令模式可以将请求封装在一个对象中,允许你可以像管理对象一样去管理方法,传递并且在合适的时机去调用他们。它的另外一个用处是,允许在服务执行的上下文中执行客户类代码。服务经常在调用客户代码的前后执行。
命令模式的主要优点如下:
- 降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦。
- 增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足“开闭原则”,对扩展比较灵活。
- 可以实现宏命令。命令模式可以与合成模式结合,将多个命令装配成一个组合命令,即宏命令。
- 方便实现 Undo 和 Redo 操作。命令模式可以与后面介绍的备忘录模式结合,实现命令的撤销与恢复。
其缺点是:可能产生大量具体命令类。因为计对每一个具体操作都需要设计一个具体命令类,这将增加系统的复杂性。