找回密码
 立即注册
首页 业界区 业界 掌握设计模式--命令模式

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

忌才砟 7 天前
命令模式(Command Pattern)

命令模式(Command Pattern)是一种行为型设计模式,它将请求(命令)封装成对象,从而使您能够参数化客户端(调用者)使用不同的请求、队列请求或者日志请求,甚至支持可撤销的操作。
核心思想将请求封装成对象,从而使得调用者与接收者解耦,同时支持请求的存储、撤销、重做和排队执行。
主要组成部分


  • Command(命令接口):通常是一个接口,定义一个执行命令的 execute() 方法。
  • ConcreteCommand(具体命令):实现命令接口,并定义执行该命令的具体操作,通常将请求的接收者(Receiver)和操作绑定在一起。
  • Client(客户端):创建一个具体命令对象并设置其接收者(Receiver)。
  • Invoker(调用者):请求命令的执行。通常在用户操作时,会调用 execute() 方法。
  • Receiver(接收者):知道如何实施与执行一个请求相关的操作,实际的业务逻辑通常由此类执行。
案例实现

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

1.png

命令调用者类依赖于命令接口,命令接口下的具体命令类操作实际的业务逻辑。
Command接口
  1. public interface Command {
  2.     void execute();
  3.     void undo();
  4. }
复制代码
绘制图形命令
  1. // ConcreteCommand - 绘制图形命令
  2. public class DrawShapeCommand implements Command {
  3.     private Shape shape;
  4.     public DrawShapeCommand(Shape shape) {
  5.         this.shape = shape;
  6.     }
  7.     @Override
  8.     public void execute() {
  9.         shape.draw();
  10.     }
  11.     @Override
  12.     public void undo() {
  13.         shape.erase();
  14.     }
  15. }
  16. // ConcreteCommand - 删除图形命令
  17. class EraseShapeCommand implements Command {
  18.     private Shape shape;
  19.     public EraseShapeCommand(Shape shape) {
  20.         this.shape = shape;
  21.     }
  22.     @Override
  23.     public void execute() {
  24.         shape.erase();
  25.     }
  26.     @Override
  27.     public void undo() {
  28.         shape.draw();
  29.     }
  30. }
复制代码
接受者--抽象图形类
  1. public abstract class Shape {
  2.     protected String name;
  3.     public abstract void draw();
  4.     public abstract void erase();
  5. }
复制代码
接受者--具体图形类
  1. public class Circle extends Shape {
  2.     public Circle() {
  3.         this.name = "Circle";
  4.     }
  5.     @Override
  6.     public void draw() {
  7.         System.out.println("绘制图形 " + name);
  8.     }
  9.     @Override
  10.     public void erase() {
  11.         System.out.println("擦除图形 " + name);
  12.     }
  13. }
  14. class Rectangle extends Shape {
  15.     public Rectangle() {
  16.         this.name = "Rectangle";
  17.     }
  18.     @Override
  19.     public void draw() {
  20.         System.out.println("绘制图形 " + name);
  21.     }
  22.     @Override
  23.     public void erase() {
  24.         System.out.println("擦除图形 " + name);
  25.     }
  26. }
复制代码
命令调用者
  1. public class CommandInvoker {
  2.     private Stack<Command> commandHistory = new Stack<>();
  3.     public void executeCommand(Command command) {
  4.         command.execute();
  5.         commandHistory.push(command);
  6.     }
  7.     public void undo() {
  8.         if (!commandHistory.isEmpty()) {
  9.             Command lastCommand = commandHistory.pop();
  10.             lastCommand.undo();
  11.         } else {
  12.             System.out.println("No commands to undo.");
  13.         }
  14.     }
  15. }
复制代码
测试代码
  1. public class CommandDemo {
  2.     public static void main(String[] args) {
  3.         // 创建图形
  4.         Shape circle = new Circle();
  5.         Shape rectangle = new Rectangle();
  6.         // 创建命令
  7.         Command drawCircleCommand = new DrawShapeCommand(circle);
  8.         Command drawRectangleCommand = new DrawShapeCommand(rectangle);
  9.         Command eraseCircleCommand = new EraseShapeCommand(circle);
  10.         Command eraseRectangleCommand = new EraseShapeCommand(rectangle);
  11.         // 创建命令调用者
  12.         CommandInvoker invoker = new CommandInvoker();
  13.         // 执行命令
  14.         invoker.executeCommand(drawCircleCommand);  // 绘制圆形
  15.         invoker.executeCommand(drawRectangleCommand);  // 绘制矩形
  16.         invoker.executeCommand(eraseCircleCommand);  // 删除圆形
  17.         invoker.executeCommand(eraseRectangleCommand);  // 删除矩形
  18.         // 撤销操作
  19.         invoker.undo();  // 撤销删除矩形
  20.         invoker.undo();  // 撤销删除圆形
  21.         invoker.undo();  // 撤销绘制矩形
  22.         invoker.undo();  // 撤销绘制圆形
  23.         invoker.undo();
  24.     }
  25. }
复制代码
测试结果

绘制图形 Circle
绘制图形 Rectangle
擦除图形 Circle
擦除图形 Rectangle
绘制图形 Rectangle
绘制图形 Circle
擦除图形 Rectangle
擦除图形 Circle
No commands to undo.
优缺点和适用场景

优点:


  • 解耦请求者和接收者:请求者(客户端)不需要知道接收者的具体实现,只需要知道命令接口。
  • 支持撤销操作:可以将命令对象设计为支持撤销的操作,使得某些操作能够撤回。
  • 可以将命令参数化:命令可以作为参数传递,或被存储起来,支持批量操作。
  • 扩展性好:增加新的命令时,不需要改变现有代码,只需要新增具体命令类。
缺点:


  • 增加类的数量:每个具体命令类都需要创建一个类,可能导致类的数量增多。
  • 实现复杂度:如果系统中的命令非常多,可能导致命令类实现过于复杂。
命令模式在 GUI 程序、事务管理、队列任务等场景中非常常见。
适用场景


  • 需要解耦请求者和接收者。
  • 需要撤销、重做操作。
  • 需要存储请求、支持队列、日志功能。
  • 需要动态选择操作或扩展操作。
  • 需要将多个操作封装为一个命令。
  • 需要管理跨平台或多设备的操作。
总结

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

  • 行为封装:命令模式将请求、操作或事务封装为命令对象,这些对象可以被请求者调用。请求者不关心具体操作的执行方式,只需要调用命令对象的执行方法即可。
  • 请求者和执行者解耦:通过引入命令对象,调用者和被调用者的关系被解耦,调用者不需要知道如何执行操作,也不需要知道具体的操作是什么,只需要发出命令请求。
2.gif

需要查看往期设计模式文章的,可以在个人主页中或者文章开头的集合中查看,可关注我,持续更新中。。。
超实用的SpringAOP实战之日志记录
2023年下半年软考考试重磅消息
通过软考后却领取不到实体证书?
计算机算法设计与分析(第5版)
Java全栈学习路线、学习资源和面试题一条龙
软考证书=职称证书?
软考中级--软件设计师毫无保留的备考分享

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册