当前位置: 首页 > news >正文

掌握设计模式--命令模式

命令模式(Command Pattern)

命令模式(Command Pattern)是一种行为型设计模式,它将请求(命令)封装成对象,从而使您能够参数化客户端(调用者)使用不同的请求、队列请求或者日志请求,甚至支持可撤销的操作。

核心思想是 将请求封装成对象,从而使得调用者与接收者解耦,同时支持请求的存储、撤销、重做和排队执行。

主要组成部分

  1. Command(命令接口):通常是一个接口,定义一个执行命令的 execute() 方法。

  2. ConcreteCommand(具体命令):实现命令接口,并定义执行该命令的具体操作,通常将请求的接收者(Receiver)和操作绑定在一起。

  3. Client(客户端):创建一个具体命令对象并设置其接收者(Receiver)。

  4. Invoker(调用者):请求命令的执行。通常在用户操作时,会调用 execute() 方法。

  5. Receiver(接收者):知道如何实施与执行一个请求相关的操作,实际的业务逻辑通常由此类执行。

案例实现

一个 图形编辑器,用户可以执行对图形的操作(如绘制、擦除等),并能够撤销这些操作。

案例类图

image

命令调用者类依赖于命令接口,命令接口下的具体命令类操作实际的业务逻辑

Command接口

public interface Command {void execute();void undo();
}

绘制图形命令

// ConcreteCommand - 绘制图形命令
public class DrawShapeCommand implements Command {private Shape shape;public DrawShapeCommand(Shape shape) {this.shape = shape;}@Overridepublic void execute() {shape.draw();}@Overridepublic void undo() {shape.erase();}
}// ConcreteCommand - 删除图形命令
class EraseShapeCommand implements Command {private Shape shape;public EraseShapeCommand(Shape shape) {this.shape = shape;}@Overridepublic void execute() {shape.erase();}@Overridepublic void undo() {shape.draw();}
}

接受者--抽象图形类

public abstract class Shape {protected String name;public abstract void draw();public abstract void erase();
}

接受者--具体图形类

public class Circle extends Shape {public Circle() {this.name = "Circle";}@Overridepublic void draw() {System.out.println("绘制图形 " + name);}@Overridepublic void erase() {System.out.println("擦除图形 " + name);}
}class Rectangle extends Shape {public Rectangle() {this.name = "Rectangle";}@Overridepublic void draw() {System.out.println("绘制图形 " + name);}@Overridepublic void erase() {System.out.println("擦除图形 " + name);}
}

命令调用者

public class CommandInvoker {private Stack<Command> commandHistory = new Stack<>();public void executeCommand(Command command) {command.execute();commandHistory.push(command);}public void undo() {if (!commandHistory.isEmpty()) {Command lastCommand = commandHistory.pop();lastCommand.undo();} else {System.out.println("No commands to undo.");}}
}

测试代码

public class CommandDemo {public static void main(String[] args) {// 创建图形Shape circle = new Circle();Shape rectangle = new Rectangle();// 创建命令Command drawCircleCommand = new DrawShapeCommand(circle);Command drawRectangleCommand = new DrawShapeCommand(rectangle);Command eraseCircleCommand = new EraseShapeCommand(circle);Command eraseRectangleCommand = new EraseShapeCommand(rectangle);// 创建命令调用者CommandInvoker invoker = new CommandInvoker();// 执行命令invoker.executeCommand(drawCircleCommand);  // 绘制圆形invoker.executeCommand(drawRectangleCommand);  // 绘制矩形invoker.executeCommand(eraseCircleCommand);  // 删除圆形invoker.executeCommand(eraseRectangleCommand);  // 删除矩形// 撤销操作invoker.undo();  // 撤销删除矩形invoker.undo();  // 撤销删除圆形invoker.undo();  // 撤销绘制矩形invoker.undo();  // 撤销绘制圆形invoker.undo();}
}

测试结果

绘制图形 Circle

绘制图形 Rectangle

擦除图形 Circle

擦除图形 Rectangle

绘制图形 Rectangle

绘制图形 Circle

擦除图形 Rectangle

擦除图形 Circle

No commands to undo.

优缺点和适用场景

优点:

  1. 解耦请求者和接收者:请求者(客户端)不需要知道接收者的具体实现,只需要知道命令接口。

  2. 支持撤销操作:可以将命令对象设计为支持撤销的操作,使得某些操作能够撤回。

  3. 可以将命令参数化:命令可以作为参数传递,或被存储起来,支持批量操作。

  4. 扩展性好:增加新的命令时,不需要改变现有代码,只需要新增具体命令类。

缺点:

  1. 增加类的数量:每个具体命令类都需要创建一个类,可能导致类的数量增多。

  2. 实现复杂度:如果系统中的命令非常多,可能导致命令类实现过于复杂。

命令模式在 GUI 程序、事务管理、队列任务等场景中非常常见。

适用场景

  • 需要解耦请求者和接收者。

  • 需要撤销、重做操作。

  • 需要存储请求、支持队列、日志功能。

  • 需要动态选择操作或扩展操作。

  • 需要将多个操作封装为一个命令。

  • 需要管理跨平台或多设备的操作。

总结

命令模式的核心关注点是将请求封装成对象,从而使得请求的发送者(调用者)和接收者(执行者)解耦。命令模式通过把请求封装成命令对象,使得你可以在不改变请求者的情况下改变请求的执行方式、顺序或者操作对象。

  • 行为封装:命令模式将请求、操作或事务封装为命令对象,这些对象可以被请求者调用。请求者不关心具体操作的执行方式,只需要调用命令对象的执行方法即可。

  • 请求者和执行者解耦:通过引入命令对象,调用者和被调用者的关系被解耦,调用者不需要知道如何执行操作,也不需要知道具体的操作是什么,只需要发出命令请求。

文章转载自:渊渟岳

原文链接:掌握设计模式--命令模式 - 渊渟岳 - 博客园

体验地址:JNPF快速开发平台

http://www.xdnf.cn/news/1345285.html

相关文章:

  • WebRTC 结合云手机:释放实时通信与虚拟手机的强大协同效能
  • elasticsearch的使用
  • C#_高性能内存处理:Span<T>, Memory<T>, ArrayPool
  • vue vxe-gantt 甘特图自定义任务条样式模板 table 自定义插槽模板
  • Vue2 响应式系统设计原理与实现
  • 【Java并发编程】Java多线程深度解析:状态、通信与停止线程的全面指南
  • 多态(polymorphism)
  • celery
  • 学习python第12天
  • 基于Python的伊人酒店管理系统 Python+Django+Vue.js
  • 探索Thompson Shell:Unix初代Shell的智慧
  • Linux之Ubuntu入门:Vmware中虚拟机中的Ubuntu中的shell命令-常用命令
  • 解决 PyTorch 导入错误:undefined symbol: iJIT_NotifyEvent
  • MTK Linux DRM分析(十一)- MTK KMS Panel显示屏驱动
  • 使用html+css+javascript练习项目布局--创建导航栏
  • Linux驱动开发笔记(六)——pinctrl GPIO
  • MTK Linux DRM分析(十三)- Mediatek KMS实现mtk_drm_drv.c(Part.1)
  • chapter07_初始化和销毁方法
  • 【连接器专题】连接器接触界面的理解
  • CoreShop微信小程序商城框架开启多租户-添加一个WPF客户端以便进行本地操作--读取店铺信息(6)
  • 彩笔运维勇闯机器学习--最小二乘法的数学推导
  • 在线教育领域的视频弹题功能如何打造高互动性在线课程
  • 【Tech Arch】Hadoop YARN 大数据集群的 “资源管家”
  • 全栈开发:从LAMP到云原生的技术革命
  • Kali Linux 发布重构版Vagrant镜像:通过命令行快速部署预配置DebOS虚拟机
  • Pandas中的SettingWithCopyWarning警告出现原因及解决方法
  • DbLens:告别手动Mock数据,右键一键智能生成数据库内容
  • httpclient与hertzclient在处理Host header时的差别
  • 【GPT入门】第53课 LlamaFactory微调效果与vllm部署效果不一致问题解决
  • open webui源码分析6-Function