【设计模式】JAVA Design Patterns——Command(事务模式)

简介: 【设计模式】JAVA Design Patterns——Command(事务模式)

🔍目的


将请求封装为对象,从而使你可以将具有不同请求的客户端参数化,队列或记录请求,并且支持可撤销操作。


🔍解释


真实世界例子

有一个巫师在地精上施放咒语。咒语在地精上一一执行。第一个咒语使地精缩小,第二个使他不可见。然后巫师将咒语一个个的反转。这里的每一个咒语都是一个可撤销的命令对象。


通俗描述

用命令对象的方式存储请求以在将来时可以执行它或撤销它。


维基百科

在面向对象编程中,命令模式是一种行为型设计模式,它把在稍后执行的一个动作或触发的一个事件所需要的所有信息封装到一个对象中。


程序示例

创建一个巫师类

public class Wizard {
 
  private static final Logger LOGGER = LoggerFactory.getLogger(Wizard.class);
 
  private final Deque<Runnable> undoStack = new LinkedList<>();
  private final Deque<Runnable> redoStack = new LinkedList<>();
 
  public Wizard() {}
 
  public void castSpell(Command command, Target target) {
    LOGGER.info("{} casts {} at {}", this, command, target);
    command.execute(target);
    undoStack.offerLast(command);
  }
 
  public void undoLastSpell() {
    if (!undoStack.isEmpty()) {
      var previousSpell = undoStack.pollLast();
      redoStack.offerLast(previousSpell);
      LOGGER.info("{} undoes {}", this, previousSpell);
      previousSpell.undo();
    }
  }
 
  public void redoLastSpell() {
    if (!redoStack.isEmpty()) {
      var previousSpell = redoStack.pollLast();
      undoStack.offerLast(previousSpell);
      LOGGER.info("{} redoes {}", this, previousSpell);
      previousSpell.redo();
    }
  }
 
  @Override
  public String toString() {
    return "Wizard";
  }
}


创建咒语层级

public interface Command {
 
  void execute(Target target);
 
  void undo();
 
  void redo();
 
  String toString();
}
 
public class InvisibilitySpell implements Command {
 
  private Target target;
 
  @Override
  public void execute(Target target) {
    target.setVisibility(Visibility.INVISIBLE);
    this.target = target;
  }
 
  @Override
  public void undo() {
    if (target != null) {
      target.setVisibility(Visibility.VISIBLE);
    }
  }
 
  @Override
  public void redo() {
    if (target != null) {
      target.setVisibility(Visibility.INVISIBLE);
    }
  }
 
  @Override
  public String toString() {
    return "Invisibility spell";
  }
}
 
public class ShrinkSpell implements Command {
 
  private Size oldSize;
  private Target target;
 
  @Override
  public void execute(Target target) {
    oldSize = target.getSize();
    target.setSize(Size.SMALL);
    this.target = target;
  }
 
  @Override
  public void undo() {
    if (oldSize != null && target != null) {
      var temp = target.getSize();
      target.setSize(oldSize);
      oldSize = temp;
    }
  }
 
  @Override
  public void redo() {
    undo();
  }
 
  @Override
  public String toString() {
    return "Shrink spell";
  }
}


创建咒语的目标:地精

public abstract class Target {
 
  private static final Logger LOGGER = LoggerFactory.getLogger(Target.class);
 
  private Size size;
 
  private Visibility visibility;
 
  public Size getSize() {
    return size;
  }
 
  public void setSize(Size size) {
    this.size = size;
  }
 
  public Visibility getVisibility() {
    return visibility;
  }
 
  public void setVisibility(Visibility visibility) {
    this.visibility = visibility;
  }
 
  @Override
  public abstract String toString();
 
  public void printStatus() {
    LOGGER.info("{}, [size={}] [visibility={}]", this, getSize(), getVisibility());
  }
}
 
public class Goblin extends Target {
 
  public Goblin() {
    setSize(Size.NORMAL);
    setVisibility(Visibility.VISIBLE);
  }
 
  @Override
  public String toString() {
    return "Goblin";
  }
 
}


实践示例

var wizard = new Wizard();
var goblin = new Goblin();
goblin.printStatus();
// Goblin, [size=normal] [visibility=visible]
wizard.castSpell(new ShrinkSpell(), goblin);
// Wizard casts Shrink spell at Goblin
goblin.printStatus();
// Goblin, [size=small] [visibility=visible]
wizard.castSpell(new InvisibilitySpell(), goblin);
// Wizard casts Invisibility spell at Goblin
goblin.printStatus();
// Goblin, [size=small] [visibility=invisible]
wizard.undoLastSpell();
// Wizard undoes Invisibility spell
goblin.printStatus();
// Goblin, [size=small] [visibility=visible]


🔍类图

74ba66885d8b4b11ac7faad0ab92fb11.png


🔍适用场景

使用命令模式情况:

  • 通过操作将对象参数化。您可以使用回调函数(即,已在某处注册以便稍后调用的函数)以过程语言表示这种参数化。命令是回调的一种面向对象替代方案。
  • 在不同的时间指定,排队和执行请求。一个命令对象的生存期可以独立于原始请求。如果请求的接收方可以以地址空间无关的方式来表示,那么你可以将请求的命令对象传输到其他进程并在那里执行请求。
  • 支持撤销。命令的执行操作可以在命令本身中存储状态以反转其效果。命令接口必须有添加的反执行操作,该操作可以逆转上一次执行调用的效果。执行的命令存储在历史列表中。无限撤消和重做通过分别向后和向前遍历此列表来实现,分别调用unexecute和execute。
  • 支持日志记录更改,以便在系统崩溃时可以重新应用它们。通过使用加载和存储操作扩展命令接口,你可以保留更改的永久日志。从崩溃中恢复涉及从磁盘重新加载记录的命令,并通过执行操作重新执行它们。
  • 通过原始的操作来构建一个以高级操作围绕的系统。这种结构在支持事务的信息系统中很常见。事务封装了一组数据更改。命令模式提供了一种对事务进行建模的方法。命令具有公共接口,让你以相同的方式调用所有事务。该模式还可以通过新的事务来轻松扩展系统。

8724ef1944dc4e9b9f2ad9efd7014784.gif

相关文章
|
20天前
|
设计模式 Java 数据库连接
【重温设计模式】代理模式及其Java示例
【重温设计模式】代理模式及其Java示例
|
2天前
|
设计模式 存储 安全
Java中的23种设计模式
Java中的23种设计模式
5 1
|
15天前
|
JavaScript Java 测试技术
Java项目基于ssm+vue.js的校园事务自助指南服务系统附带文章和源代码设计说明文档ppt
Java项目基于ssm+vue.js的校园事务自助指南服务系统附带文章和源代码设计说明文档ppt
11 0
|
17天前
|
设计模式 存储 前端开发
Java的mvc设计模式在web开发中应用
Java的mvc设计模式在web开发中应用
|
17天前
|
存储 前端开发 Java
Java一分钟之-Java GUI设计原则与模式
本文介绍了Java GUI开发的核心设计原则和模式,包括分层架构(MVC)、组件复用、用户体验和代码示例。强调了MVC模式以提高代码可维护性,组件化设计以增强复用性,以及响应式和简洁界面以提升用户体验。同时,提出了常见问题的避免策略,如布局管理、资源释放和国际化支持,建议开发者遵循这些原则以提升GUI应用质量。
53 3
|
19天前
|
设计模式 安全 Java
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
该文介绍了一种C++的编程技巧——奇异递归模板模式(CRTP),旨在让派生组件能继承基本组件的特定功能。通过示例展示了如何创建一个`Fighter`接口和`MmaFighter`类,其中`MmaFighter`及其子类如`MmaBantamweightFighter`和`MmaHeavyweightFighter`强制类型安全,确保相同重量级的拳手之间才能进行比赛。这种设计避免了不同重量级拳手间的错误匹配,编译时会报错。CRTP适用于处理类型冲突、参数化类方法和限制方法只对相同类型实例生效的情况。
【设计模式】JAVA Design Patterns——Curiously Recurring Template Pattern(奇异递归模板模式)
|
24天前
|
设计模式 Java API
【设计模式】JAVA Design Patterns——Combinator(功能模式)
【设计模式】JAVA Design Patterns——Combinator(功能模式)
|
24天前
|
设计模式 监控 Java
【设计模式】JAVA Design Patterns——Circuit Breaker(断路器模式)
【设计模式】JAVA Design Patterns——Circuit Breaker(断路器模式)
|
24天前
|
设计模式 Java 程序员
【设计模式】JAVA Design Patterns——Bytecode(字节码模式)
【设计模式】JAVA Design Patterns——Bytecode(字节码模式)
|
24天前
|
设计模式 算法 Java
【设计模式】JAVA Design Patterns——Builder(构造器模式)
【设计模式】JAVA Design Patterns——Builder(构造器模式)