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

【设计模式】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();}}@Overridepublic 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;@Overridepublic void execute(Target target) {target.setVisibility(Visibility.INVISIBLE);this.target = target;}@Overridepublic void undo() {if (target != null) {target.setVisibility(Visibility.VISIBLE);}}@Overridepublic void redo() {if (target != null) {target.setVisibility(Visibility.INVISIBLE);}}@Overridepublic String toString() {return "Invisibility spell";}
}public class ShrinkSpell implements Command {private Size oldSize;private Target target;@Overridepublic void execute(Target target) {oldSize = target.getSize();target.setSize(Size.SMALL);this.target = target;}@Overridepublic void undo() {if (oldSize != null && target != null) {var temp = target.getSize();target.setSize(oldSize);oldSize = temp;}}@Overridepublic void redo() {undo();}@Overridepublic 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;}@Overridepublic 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);}@Overridepublic 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]

🔍类图

🔍适用场景

使用命令模式情况:

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

相关文章:

  • MySQL视图教程(01):创建视图
  • YOLOv10 论文学习
  • 一.架构设计
  • 互联网十万个为什么之什么是虚拟化?
  • kubenetes中K8S的命名空间状态异常强制删除Terminating的ns
  • 架构师必考题--软件系统质量属性
  • 【蓝桥杯】国赛普及-
  • 变分自动编码器(VAE)深入理解与总结
  • ffplay 使用文档介绍
  • js 生成二维码
  • Spring Boot:SpringBoot 如何优雅地定制JSON响应数据返回
  • 民国漫画杂志《时代漫画》第16期.PDF
  • 虹科Pico汽车示波器 | 免拆诊断案例 | 2012 款雪佛兰科鲁兹车偶尔多个故障灯异常点亮
  • 27【Aseprite 作图】盆栽——拆解
  • 重学java 43.多线程 多等待多唤醒案例
  • 「译」Node.js Streams 基础
  • 03Go 类型总结
  • Date型的使用
  • es6--symbol
  • golang中接口赋值与方法集
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • JavaWeb(学习笔记二)
  • Mithril.js 入门介绍
  • node-glob通配符
  • NSTimer学习笔记
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • VUE es6技巧写法(持续更新中~~~)
  • 利用jquery编写加法运算验证码
  • 聊聊sentinel的DegradeSlot
  • 使用Gradle第一次构建Java程序
  • 手写一个CommonJS打包工具(一)
  • 正则表达式
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • ionic入门之数据绑定显示-1
  • ​zookeeper集群配置与启动
  • # 移动硬盘误操作制作为启动盘数据恢复问题
  • #、%和$符号在OGNL表达式中经常出现
  • #1014 : Trie树
  • (4)事件处理——(7)简单事件(Simple events)
  • (补)B+树一些思想
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (求助)用傲游上csdn博客时标签栏和网址栏一直显示袁萌 的头像
  • (三)Honghu Cloud云架构一定时调度平台
  • (四)activit5.23.0修复跟踪高亮显示BUG
  • (四)docker:为mysql和java jar运行环境创建同一网络,容器互联
  • (转)自己动手搭建Nginx+memcache+xdebug+php运行环境绿色版 For windows版
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • .“空心村”成因分析及解决对策122344
  • .NET Project Open Day(2011.11.13)
  • .net分布式压力测试工具(Beetle.DT)
  • /usr/bin/perl:bad interpreter:No such file or directory 的解决办法
  • @Autowired 和 @Resource 区别的补充说明与示例