Memento模式(备忘录设计模式)
Memento模式?
使用面向对象编程的方式实现撤销功能时,需要事先保存实例的相关状态信息。然后,在撤销时,还需要根据所保存的信息将实例恢复至原来的状态。这个时候你需要使用Memento设计模式。(以及实例实现对状态的保存)
关键字:
1.·Undo(撤销)
2.·Redo(重做)
3.·History(历史记录)
4。·Snapshot(快照)破坏封装性:
将依赖于实例内部结构的代码分散地编写在程序中的各个地方,导致程序变得难以维护。宽窄接口
- wide interface——宽接口(APl)Memento角色提供的“宽接口(API)”是指所有用于获取恢复对象状态信息的方法的集合。由于宽接口(API)会暴露所有Memento角色的内部信息,因此能够使用宽接口(API)的只有Originator角色。
- narrowinterface——窄接口(API)Memento角色为外部的Caretaker角色提供了“窄接口(API)”。可以通过窄接口(API)获取的Memento角色的内部信息非常有限,因此可以有效地防止信息泄露。
通过对外提供以上两种接口(API),可以有效地防止对象的封装性被破坏
- 相关设计模式
1.Command模式(第22章)在使用Command模式处理命令时,可以使用Memento模式实现撤销功能。
2.Protype模式(第6章)在Memento模式中,为了能够实现快照和撤销功能,保存了对象当前的状态。保存的信息只是在恢复状态时所需要的那部分信息。
而在Protype模式中,会生成一个与当前实例完全相同的另外一个实例。这两个实例的内容完全一样。
- State模式(第19章)在Memento模式中,是用“实例”表示状态。而在State模式中,则是用“类”表示状态。
理清职责
- 实现功能
- ·游戏是自动进行的
- ·游戏的主人公通过掷骰子来决定下一个状态
- ·当骰子点数为1的时候,主人公的金钱会增加·当骰子点数为2的时候,主人公的金钱会减少
- ·当骰子点数为6的时候,主人公会得到水果
- ·主人公没有钱时游戏就会结束
包>>>名字=>>>说明
game |Memento|表示Gamer状态的类
game |Gamer表示游戏主人公的类。它会生成Memento的实例进行游戏的类。它会事先保存Memento的实例,之后会根据需要恢复Gamer的状态
null | MainT 这里为了方便起见使用MainT作为责任人保存用户状态
UML

时序图:

Code
- Gamer
public class Gamer {
/**
* 下面的money 与 fruits 就是按照一般的定义方式去定义
* 但是我们提取Memento的时候需要注意这个的获取规则
*/
// 获得金钱
private int money;
// 获得的水果
private List<String> fruits=new ArrayList<>();
private Random random=new Random();
private final static String[] fruitname=new String[]{
"苹果","葡萄","香蕉","橘子"
};
public Gamer(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
/**
* 开始游戏
* 骰子结果1,2 ,6进行不同的操作
*/
public void bet(){
int dice=random.nextInt(6)+1;
if(dice==1){
this.money+=100;
System.out.println("金钱增加了!");
}else if(dice==2){
this.money/=2;
System.out.println("金钱减半了!");
}else if(dice==6){
String f=getFruit();
System.out.println("获得了水果["+f+"]!");
this.fruits.add(f);
}else{
System.out.println("什么也不发生");
}
}
/**
* 快照方法
*/
public Memento createMemento(){
Memento memento = new Memento(this.money);
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()){
String s = iterator.next();
if(s.startsWith("好吃的")){
memento.addFruit(s);
}
}
return memento;
}
/**
* 撤销方法
*/
public void restoreMemento(Memento memento){
this.money=memento.money;
this.fruits=memento.fruits;
}
private String getFruit() {
String prefix="";
if(random.nextBoolean()){
prefix="好吃的";
}
return prefix+fruitname[random.nextInt(fruitname.length)];
}
@Override
public String toString() {
return "Gamer{" +
"money=" + money +
", fruits=" + fruits +
'}';
}
}
- Memento
public class Memento {
/**
* 使用过程中因为Memento与Gamer是强关联关系,但是又因为是在同一个game包下,
* 使用可见性修饰符显得比较重要:
* 这里的两个字段在同一个包下都是可以访问
*/
int money;
ArrayList<String> fruits;
/**
* 窄接口
*/
public int getMoney(){
return money;
}
/**
* 这里是宽接口
* @param money
*/
Memento(int money) {
this.money = money;
this.fruits = new ArrayList<>();
}
/**
* 这里是宽接口
*/
void addFruit(String fruit){
fruits.add(fruit);
}
/**
* 这里是宽接口
*/
ArrayList<String> getFruits(){
return (ArrayList<String>) fruits.clone();
}
}
- MainT
public class MainT {
/**
* 这里的状态只是单个快照点,当你需要多个快照点的时候,
* 单独创建一个snapshot类来管理,可以使用集合等,
* 这里写个例子
*/
public static void main(String[] args) {
Gamer gamer = new Gamer(100);
//保存的一个快照 初始状态
Memento memento = gamer.createMemento();
for (int i = 0; i < 100; i++) {
System.out.println("===="+i);
System.out.println("当前状态"+gamer);
//开始游戏
gamer.bet();
System.out.println("还有多少钱"+gamer.getMoney()+"元");
if(gamer.getMoney()>memento.getMoney()){
System.out.println("//保存新状态");
memento=gamer.createMemento();
}else if(gamer.getMoney()<memento.getMoney()/2){
System.out.println("金钱减少一半了,恢复到原来的状态");
gamer.restoreMemento(memento);
}
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
public class SnapShotManger implements Serializable {
private List<Memento> mementos=new ArrayList<>();
/**
* 实现java.io.Serializable接口
* 用objectoutputstream的writeobject方法
* 用objectInputStream的 readobject方法
*/
/**
* 保存
*/
/**
* 恢复
*/
}
Memento模式(备忘录设计模式)的更多相关文章
- 《图解设计模式》读书笔记8-2 MEMENTO模式
目录 Memento模式 示例代码 程序类图 代码 角色和类图 模式类图 角色 思路拓展 接口可见性 保存多少个Memento 划分Caretaker和Originator的意义 Memento模式 ...
- Java设计模式(15)备忘录模式(Memento模式)
Memento定义:memento是一个保存另外一个对象内部状态拷贝的对象,这样以后就可以将该对象恢复到原先保存的状态. Memento模式相对也比较好理解,我们看下列代码: public class ...
- C++设计模式实现--备忘录(Memento)模式
一. 备忘录模式 定义:在不破坏封装性的前提下,捕获一个对象的内部状态.并在该对象之外保存这个状态. 这样以后就可将该对象恢复到原先保存的状态. 结构图: 使用范围: Memento 模式比較适用于功 ...
- 设计模式C++描述----17.备忘录(Memento)模式
一. 备忘录模式 定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 结构图: 使用范围: Memento 模式比较适用于功能 ...
- 设计模式之美:Memento(备忘录)
索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Memento 模式结构样式代码. 别名 Token 意图 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这 ...
- 备忘录(Memento)模式
备忘录模式又叫做快照模式或者Token模式. 备忘录对象是一个用来存储另一个对象内部状态的快照的对象.备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化,存储起来,从而可以在将来 ...
- 设计模式之——Memento模式
Memento模式即快照模式,就是在某一时刻,设定一个状态,在后面随时可以返回到当前状态的模式. 我们拿一个闯关游戏作为举例,一共有十关,每闯一关,玩家所持金额增加一百,而闯关失败就扣一百.初始时,给 ...
- 设计模式(十八)Memento模式
在使用面向对象编程的方式实现撤销功能时,需要事先保存实例的相关状态信息.然后,在撤销时,还需要根据所保存的信息将实例恢复至原来的状态. 要想恢复实例,需要一个可以自由访问实例内部结构的权限.但是,如果 ...
- 【行为型】Memento模式
备忘录模式顾名思义就是一种能有备忘作用的设计模式,其目的是在对象外部保存其在某一时刻的状态信息,并且在任何需要的时候,都可以通过备忘录中保存的状态数据恢复对象在当时情形下的状态. 备忘录模式旨在对象的 ...
随机推荐
- uva1160 易爆物
#include<iostream>#include<cstdio>#include<algorithm>#include<cstdlib>using ...
- MYSQL root密码修改找回命令
方法1: 用SET PASSWORD命令 mysql -u root mysql> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('newpass ...
- Popular Cows
传送门(poj):http://poj.org/problem?id=2186 (bzoj):http://www.lydsy.com/JudgeOnline/problem.php?id=1051 ...
- 一步一步学RenderMonkey
http://blog.csdn.net/tianhai110/article/details/5668832 转载请注明出处:http://blog.csdn.net/tianhai110/ 网上一 ...
- BZOJ3401:[USACO2009MAR]Look Up
浅谈栈:https://www.cnblogs.com/AKMer/p/10278222.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?id ...
- C/C++的区别
C和C++的关系:就像是win98跟winXP的关系.C++是在C的基础上增加了新的理论,玩出了新的花样.所以叫C加加. C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设 ...
- C语言学习笔记--C语言中变量的属性关键字
变量属性关键字的使用语法:property type var_name; 1.auto 关键字 auto关键字是C语言中局部变量的默认的关键字,C编译器默认所有的局部变量都是auto的,它表明了被修饰 ...
- 对vuex的理解
我用的vue安装了一个插件vuex插件 有3个 文件夹分别是actions(用于数据请求),getters(用于监听store),store(用于存储数据),
- 由hibernate配置cascade而导致的软件错误,并分析解决此问题的过程
本文与上一篇文章的软件背景相同,是一个安装部署的工具,这个工具会生成整套系统部署用的xml文件. 这个工具中有一个“克隆”功能,当安装包有新版本后,可以克隆之前的xml版本,并在其基础上做少许修改来适 ...
- 项目一:第三天 收派标准添加 收派标准分页查询(基于datagrid实现) 收派标准修改快递员添加 快递员列表查询
1.收派标准添加 n jQuery easyUI window使用 n jQuery easyUI form表单校验 n 收派标准添加页面调整—url params n 服务端实现—三层 2.jQue ...