观世音甘泉活树的故事竟然是Java设计模式:备忘录模式
定义
备忘录模式是对象的行为型模式,备忘录对象是一个用来存储另外一个对象内部状态的快照的对象,备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化存储起来,从而可以使得在将来合适的时候把这个对象还原到存储起来的状态
意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态
主要解决问题
在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态
何时使用
很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃
优缺点
优点:
- 有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这个时候使用备忘录模式,可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以保持封装的边界
- 当发起人角色的状态改变时,有可能这个状态无效,这个时候就可以使用暂时存储起来的备忘录将状态复原
缺点:
消耗资源。如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存
结构
涉及的角色:
备忘录(Memento)角色:
- 将发起人(Originator)对象的内部状态存储起来;备忘录可以根据发起人对象的判断来决定存储多少发起人(Originator)对象的内部状态
- 备忘录可以保护其内容不被发起人(Originator)对象之外的任何对象所读取,备忘录有两个等效的接口:
- 窄接口:负责人(Caretaker)对象和其他除发起人对象之外的任何对象,看到的是备忘录的窄接口,这个接口只允许它把备忘录对象传给其他的对象
- 宽接口:发起人对象可以看到一个宽接口,这个宽接口允许它读取所有的数据,以便根据这些数据恢复发起人对象的内部状态
发起人(Originator)角色:
- 创建一个含有当前的内部状态的备忘录对象
- 使用备忘录对象存储其内部状态
负责人(Caretaker)角色:
- 负责保存备忘录对象
- 不检查备忘录对象的内容
白箱实现
将发起人角色的状态存储在一个大家都看的到的地方,因此是破坏封装性的
源码如下:
public class Originator {
private String state;
/** 返回一个新的备忘录对象 */
public Memento createMemento() {
return new Memento(state);
}
/** 将发起人恢复到备忘录对象所记录的状态 */
public void restoreMemento(Memento memento) {
this.state = memento.getState();
}
/** 状态的取值方法 */
public String getState() {
return this.state;
}
/** 状态的赋值方法 */
public void setState(String state) {
this.state = state;
System.out.println("当前状态:" + this.state);
}
}
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
/** 状态的取值方法 */
public String getState() {
return this.state;
}
/** 状态的赋值方法 */
public void setState(String state) {
this.state = state;
}
}
public class Caretaker {
private Memento memento;
/** 备忘录的取值方法 */
public Memento getMemento() {
return this.memento;
}
/** 备忘录的赋值方法 */
public void setMemento(Memento memento) {
this.memento = memento;
}
}
public class Client {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
//改变发起人对象的状态
originator.setState("On");
//创建备忘录对象,并将发起人对象的状态存储起来
caretaker.setMemento(originator.createMemento());
//修改发起人对象的状态
originator.setState("Off");
originator.restoreMemento(caretaker.getMemento());
//恢复发起人对象的状态
System.out.println("恢复状态:" + originator.getState());
}
}
黑箱实现
将Memento类设成Originator类的内部类,在外部提供一个标识接口MementoIF给Caretaker类以及其他对象
源码如下:
public class Originator {
private String state;
public Originator() {
}
/** 返回一个新的备忘录对象 */
public MementoIF createMemento() {
return new Memento(this.state);
}
/** 将发起人恢复到备忘录对象所记录的状态 */
public void restoreMemento(MementoIF memento) {
Memento memento1 = (Memento) memento;
this.state = memento1.getState();
}
/** 状态的取值方法 */
public String getState() {
return this.state;
}
/** 状态的赋值方法 */
public void setState(String state) {
this.state = state;
System.out.println("当前状态:" + this.state);
}
/** 内部成员类,备忘录 */
protected class Memento implements MementoIF {
private String saveState;
private Memento(String state) {
this.saveState = state;
}
/** 状态的取值方法 */
private String getState() {
return this.saveState;
}
/** 状态的赋值方法 */
private void setState(String state) {
this.saveState = state;
}
}
}
public interface MementoIF {
}
public class Caretaker {
private MementoIF memento;
/** 备忘录的取值方法 */
public MementoIF getMemento() {
return this.memento;
}
/** 备忘录的赋值方法 */
public void setMemento(MementoIF memento) {
this.memento = memento;
}
}
public class Client {
private static Originator o = new Originator();
private static Caretaker c = new Caretaker();
public static void main(String[] args) {
//改变发起人对象的状态
o.setState("On");
//创建备忘录对象,并将发起人对象的状态存储起来
c.setMemento(o.createMemento());
//修改发起人对象的状态
o.setState("Off");
o.restoreMemento(c.getMemento());
//恢复发起人对象的状态
System.out.println("恢复状态:" + o.getState());
}
}
多重检查点
存储多个状态,或者叫做有多个检查点
public class Originator {
private Vector states;
private int index;
public Originator() {
this.states = new Vector();
this.index = 0;
}
/** 返回一个新的备忘录对象 */
public Memento createMemento() {
return new Memento(states, index);
}
/** 将发起人恢复到备忘录对象所记录的状态 */
public void restoreMemento(Memento memento) {
this.states = memento.getStates();
this.index = memento.getIndex();
}
/** 状态的赋值方法 */
public void setState(String state) {
this.states.addElement(state);
index++;
}
/** 打印出所有的状态 */
public void printStates() {
System.out.println("总的状态数量:" + index);
for (Enumeration e = states.elements(); e.hasMoreElements();) {
System.out.println(e.nextElement());
}
}
}
public class Memento {
private Vector states;
private int index;
public Memento(Vector states, int index) {
this.states = (Vector) states.clone();
this.index = index;
}
/** 状态的取值方法 */
public Vector getStates() {
return states;
}
/** 检查点指数的取值方法 */
public int getIndex() {
return index;
}
}
public class Caretaker {
private Originator originator;
private Vector vector = new Vector();
private int current;
public Caretaker(Originator originator) {
this.originator = originator;
this.current = 0;
}
/** 创建一个新的检查点 */
public int createMemento() {
Memento memento = originator.createMemento();
vector.addElement(memento);
return current++;
}
/** 将发起人恢复到某个检查点 */
public void restoreMemento(int index) {
Memento memento = (Memento) vector.elementAt(index);
originator.restoreMemento(memento);
}
/** 将某个检查点删除 */
public void removeMemento(int index) {
vector.removeElementAt(index);
}
}
public class Client {
private static Originator o = new Originator();
private static Caretaker c = new Caretaker(o);
public static void main(String[] args) {
//改变状态
o.setState("state 0");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 1");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 2");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 3");
//建立一个检查点
c.createMemento();
//打印所有的检查点
o.printStates();
//恢复到第1个检查点
System.out.println("恢复到第1个检查点");
c.restoreMemento(1);
o.printStates();
//恢复到第3个检查点
System.out.println("恢复到第2个检查点");
c.restoreMemento(2);
o.printStates();
}
}
观世音甘泉活树的故事
孙大圣保护唐僧西行,路过万寿山五庄观,与道童发生口角,一时发怒,把人参果树推倒;大圣只好请观世音菩萨救活人参果树
在这里,果树的状态保存在观世音的甘露之中,菩萨可以从甘露中把果树的状态恢复过来,果树是发起人角色,甘露是备忘录角色,菩萨是负责人角色
public class SweetSpringWater {
private String fruiterState;
public SweetSpringWater(String fruiterState) {
this.fruiterState = fruiterState;
}
/** 获取果树的状态 */
public String getFruiterState() {
return fruiterState;
}
/** 设置果树的状态 */
public void setFruiterState(String fruiterState) {
this.fruiterState = fruiterState;
}
}
public class Fruiter {
private String fruiterState;
/** 返回一个新的备忘录对象 */
public SweetSpringWater createMemento() {
return new SweetSpringWater(fruiterState);
}
/** 将发起人恢复到备忘录对象所记录的状态 */
public void restoreSweetSpringWater(SweetSpringWater springWater) {
this.fruiterState = springWater.getFruiterState();
}
/** 果树状态的取值方法 */
public String getState() {
return this.fruiterState;
}
/** 果树状态态的赋值方法 */
public void setState(String fruiterState) {
this.fruiterState = fruiterState;
System.out.println("当前果树状态:" + this.fruiterState);
}
}
public class Goddess {
private SweetSpringWater sweetSpringWater;
/** 备忘录的取值方法 */
public SweetSpringWater getSweetSpringWater() {
return this.sweetSpringWater;
}
/** 备忘录的赋值方法 */
public void setMemento(SweetSpringWater sweetSpringWater) {
this.sweetSpringWater = sweetSpringWater;
}
}
public class Client {
public static void main(String[] args) {
Fruiter f = new Fruiter();
Goddess g = new Goddess();
//改变发起人对象的状态
f.setState("果树被孙悟空推倒了");
//创建备忘录对象,并将发起人对象的状态存储起来
g.setMemento(f.createMemento());
//修改发起人对象的状态
f.setState("观世音用甘泉恢复果树状态");
//恢复发起人对象的状态
System.out.println("恢复状态:" + f.getState());
}
}
观世音甘泉活树的故事竟然是Java设计模式:备忘录模式的更多相关文章
- JAVA 设计模式 备忘录模式
用途 备忘录模式 (Memento) 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态. 这样以后就可将该对象恢复到原先保存的状态. 备忘录模式是一种行为型模式. 结构
- java设计模式---备忘录模式
一.引子 俗话说:世上难买后悔药.所以凡事讲究个"三思而后行",但总常见有人做"痛心疾首"状:当初我要是--.如果真的有<大话西游>中能时光倒流的& ...
- Java设计模式-备忘录模式(Memento)
主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象,个人觉得叫备份模式更形象些,通俗的讲下:假设有原始类A,A中有各种属性,A可以决定需要备份的属性,备忘录类B是用来存储A的一些内部状态,类C ...
- Java设计模式—备忘录模式
个人感觉备忘录模式是一个比较难的设计模式,备忘录模式就是一个对象的备份模式,提供了一种程序数据的备份方法. 定义如下:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以 ...
- Java设计模式——组合模式
JAVA 设计模式 组合模式 用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模 ...
- java设计模式--单列模式
java设计模式--单列模式 单列模式定义:确保一个类只有一个实例,并提供一个全局访问点. 下面是几种实现单列模式的Demo,每个Demo都有自己的优缺点: Demo1: /** * 单列模式需要满足 ...
- 3.java设计模式-建造者模式
Java设计模式-建造者模式 在<JAVA与模式>一书中开头是这样描述建造(Builder)模式的: 建造模式是对象的创建模式.建造模式可以将一个产品的内部表象(internal repr ...
- Java设计模式-代理模式之动态代理(附源代码分析)
Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...
- Java设计模式——外观模式
JAVA 设计模式 外观模式 用途 外观模式 (Facade) 为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 外观模式是一种结构型模式. 结构
随机推荐
- 文件I/O的内核缓冲
本文转载自文件 I/O 的内核缓冲 导语 从最粗略的角度理解 Linux 文件 I/O 内核缓冲(buffer cache),啰嗦且不严谨.只为了直观理解. 当我们说一个程序读写磁盘上的文件时,通常指 ...
- RabbitMQ之TTL(Time-To-Live 过期时间)
本文转载自RabbitMQ之TTL(Time-To-Live 过期时间) 概述 RabbitMQ可以对消息和队列设置TTL. 目前有两种方法可以设置.第一种方法是通过队列属性设置,队列中所有消息都有相 ...
- Promise和async await详解
本文转载自Promise和async await详解 Promise 状态 pending: 初始状态, 非 fulfilled 或 rejected. fulfilled: 成功的操作. rejec ...
- requests页面请求返回400:{"errors":{"username":"值必须是非空字符串。"}}
我的描述:我引入requests包,携带json类型数据请求(POST)一个网站,,访问提示<Response [400]> 解决方案: 1.首先使用postman请求一模一样的数据,发现 ...
- DQL:data query language用来查询数据库表中的数据
对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 如果没有查询条件,则每次查询所有的行.实际应用中,一般要指定查询的条件.对记录进行过滤. 查询 ...
- 微信小程序:优化页面要渲染的属性
问题:页面中只用到四个属性:goods_name,goods_price,goods_introduce,pics,但是整个对象中有22个属性,小程序中建议:data中只存放标签中要使用的数据,而现在 ...
- SpringCloud Sleuth
1.定义 Sleuth(分布式请求链路跟踪):提供了一套完整的服务跟踪解决方案,也兼容zipkin. 参考网址:https://github.com/spring-cloud/spring-cloud ...
- docker方式部署禅道
一.概述 使用docker方式部署禅道简单,快速,不容易出错.比起编译安装要方便很多. 二.部署 环境说明 操作系统:centos 7.6 ip地址:10.212.82.65 docker版本:19. ...
- Latency 和 Delay 区别
时延:Latency 指的是一个报文进入一台设备以致这台设备所经历的时间.实际上考验的是报文在这台设备上消耗的时间.时间越短,这台设备的性能越高. 延时:Delay 是指一个操作和另个一个操作之间 ...
- ant-design-vue中table自定义列
1. 使用背景 在项目中使用ant-vue的a-table控件过程中,需要显示序号列或者在列中显示图片,超链,按钮等UI信息.经过查询文档customCell和customRender可以实现以上需求 ...