初识设计模式 - 命令模式
简介
命令设计模式(Command Design Pattern)可以将请求发送者和接收者完全解耦。发送者和接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。
其定义是,将请求(命令)封装成一个对象,从而可用不同的请求对客户进行参数化(将不同请求依赖注入到其他对象),并且能够支持请求(命令)的排队执行、记录日志、撤销等(附加控制)功能。
典型实现
首先,定义一个抽象命令 Command
接口,通常仅声明一个执行命令的方法,其代码示例如下:
public interface Command { // 业务处理方法 void execute(); }
具体命令会实现各种类型的请求,其自身并不完成工作,而是将调用委派给一个业务逻辑对象,其代码示例如下:
public class ConcreteCommand implements Command { // 维持一个对请求者对象的引用 private final Receiver receiver; public ConcreteCommand(Receiver receiver) { this.receiver = receiver; } // 调用请求接收者的业务处理方法 public void execute() { this.receiver.action(); } }
接收者是真正命令执行的对象,是客户端直接操作的对象,其代码示例如下:
public class Receiver { public void action() { // 具体操作 } }
最后,需要定义的是调用者 Invoker
类,其作用是负责对请求进行初始化,其代码示例如下:
public class Invoker { private final List<Command> commandList; public Invoker() { this.commandList = new ArrayList<>(); } public Invoker(Command command) { this(); this.commandList.add(command); } // 添加命令 public void pushCommand(Command command) { this.commandList.add(command); } // 执行命令 public void executeAll() { for (Command command : commandList) { command.execute(); } commandList.clear(); } }
对于客户端而言,需要知道自己需要操作的接收者对象是什么、可以执行的命令有哪些、通过调用者如何去执行这些命令。
如下是客户端使用命令模式的代码示例:
public class CommandDemo { public static void main(String[] args) { // 操作的接收者对象是什么 Receiver receiver = new Receiver(); // 可以执行的命令有哪些 Command command = new ConcreteCommand(receiver); // 通过调用者如何去执行这些命令 Invoker invoker = new Invoker(command); invoker.executeAll(); } }
总结
优点
命令模式的主要优点如下:
- 降低请求者和接收者的耦合度
- 新的命令可以很方便地加入到系统中
- 可以比较容易地设计一个命令队列或者宏命令(组合命令)
- 为请求的撤销和恢复操作提供了一种设计和实现方案
缺点
命令模式的主要缺点如下:
- 可能会导致系统中有过多的具体命令类
适用场景
命令模式的适用场景如下:
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互
- 系统需要在不同的时间指定请求、将请求排队和执行请求
- 系统需要支持命令的撤销操作和恢复操作
- 系统需要将一组操作组合在一起形成宏命令
源码
在 JDK 中,Runnable
接口就类似于命令模式的命令接口。
只要实现了 Runnable
接口的类都被认为是一个线程类,相当于命令模式中具体命令类的角色。而实现了 Runnable
接口的 Thread
类既可以作为具体命令类,也可以作为调用者。
如下是客户端使用 Runnable
和 Thread
的代码示例:
public class ThreadDemo { public static void main(String[] args) { Runnable command = new Runnable() { @Override public void run() { System.out.println("command 线程执行"); } }; Thread thread = new Thread(command); // command 线程执行 thread.start(); } }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 【.NET】调用本地 Deepseek 模型