Memento模式?

使用面向对象编程的方式实现撤销功能时,需要事先保存实例的相关状态信息。然后,在撤销时,还需要根据所保存的信息将实例恢复至原来的状态。这个时候你需要使用Memento设计模式。(以及实例实现对状态的保存)

  • 关键字:

    1.·Undo(撤销)

    2.·Redo(重做)

    3.·History(历史记录)

    4。·Snapshot(快照)

  • 破坏封装性:

    将依赖于实例内部结构的代码分散地编写在程序中的各个地方,导致程序变得难以维护。

  • 宽窄接口

  1. wide interface——宽接口(APl)Memento角色提供的“宽接口(API)”是指所有用于获取恢复对象状态信息的方法的集合。由于宽接口(API)会暴露所有Memento角色的内部信息,因此能够使用宽接口(API)的只有Originator角色。
  2. narrowinterface——窄接口(API)Memento角色为外部的Caretaker角色提供了“窄接口(API)”。可以通过窄接口(API)获取的Memento角色的内部信息非常有限,因此可以有效地防止信息泄露。

    通过对外提供以上两种接口(API),可以有效地防止对象的封装性被破坏
  • 相关设计模式

    1.Command模式(第22章)在使用Command模式处理命令时,可以使用Memento模式实现撤销功能。

    2.Protype模式(第6章)在Memento模式中,为了能够实现快照和撤销功能,保存了对象当前的状态。保存的信息只是在恢复状态时所需要的那部分信息。

    而在Protype模式中,会生成一个与当前实例完全相同的另外一个实例。这两个实例的内容完全一样。
  1. State模式(第19章)在Memento模式中,是用“实例”表示状态。而在State模式中,则是用“类”表示状态。

理清职责

  • 实现功能
  1. ·游戏是自动进行的
  2. ·游戏的主人公通过掷骰子来决定下一个状态
  3. ·当骰子点数为1的时候,主人公的金钱会增加·当骰子点数为2的时候,主人公的金钱会减少
  4. ·当骰子点数为6的时候,主人公会得到水果
  5. ·主人公没有钱时游戏就会结束

包>>>名字=>>>说明

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模式(备忘录设计模式)的更多相关文章

  1. 《图解设计模式》读书笔记8-2 MEMENTO模式

    目录 Memento模式 示例代码 程序类图 代码 角色和类图 模式类图 角色 思路拓展 接口可见性 保存多少个Memento 划分Caretaker和Originator的意义 Memento模式 ...

  2. Java设计模式(15)备忘录模式(Memento模式)

    Memento定义:memento是一个保存另外一个对象内部状态拷贝的对象,这样以后就可以将该对象恢复到原先保存的状态. Memento模式相对也比较好理解,我们看下列代码: public class ...

  3. C++设计模式实现--备忘录(Memento)模式

    一. 备忘录模式 定义:在不破坏封装性的前提下,捕获一个对象的内部状态.并在该对象之外保存这个状态. 这样以后就可将该对象恢复到原先保存的状态. 结构图: 使用范围: Memento 模式比較适用于功 ...

  4. 设计模式C++描述----17.备忘录(Memento)模式

    一. 备忘录模式 定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 结构图: 使用范围: Memento 模式比较适用于功能 ...

  5. 设计模式之美:Memento(备忘录)

    索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Memento 模式结构样式代码. 别名 Token 意图 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这 ...

  6. 备忘录(Memento)模式

    备忘录模式又叫做快照模式或者Token模式. 备忘录对象是一个用来存储另一个对象内部状态的快照的对象.备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化,存储起来,从而可以在将来 ...

  7. 设计模式之——Memento模式

    Memento模式即快照模式,就是在某一时刻,设定一个状态,在后面随时可以返回到当前状态的模式. 我们拿一个闯关游戏作为举例,一共有十关,每闯一关,玩家所持金额增加一百,而闯关失败就扣一百.初始时,给 ...

  8. 设计模式(十八)Memento模式

    在使用面向对象编程的方式实现撤销功能时,需要事先保存实例的相关状态信息.然后,在撤销时,还需要根据所保存的信息将实例恢复至原来的状态. 要想恢复实例,需要一个可以自由访问实例内部结构的权限.但是,如果 ...

  9. 【行为型】Memento模式

    备忘录模式顾名思义就是一种能有备忘作用的设计模式,其目的是在对象外部保存其在某一时刻的状态信息,并且在任何需要的时候,都可以通过备忘录中保存的状态数据恢复对象在当时情形下的状态. 备忘录模式旨在对象的 ...

随机推荐

  1. 本机不装Oracle,使用plsql连接远程Oracle的方法

    由于Oracle的庞大,有时候我们需要在只安装Oracle客户端如plsql.toad等的情况下去连接远程数据库,可是没有安装Oracle就没有一切的配置文件去支持.最后终于发现一个很有效的方法,Or ...

  2. 原来问题在这里-我的memory leak诊断历程

    自从公司开始将java作为主要开发语言后,C++与java的混合应用日趋增多. java与C++的通信主要也是使用JNI来完成,这并没有什么问题.对于这样的混合应用项目来说,最大的噩梦莫过于memor ...

  3. margin百分比的相对值--宽度!

    假设一个块级包含容器,宽1000px,高600px,块级子元素定义 margin:10% 5%; 那么 margin的 top, right, bottom, left 计算值最终是多少px? 不是1 ...

  4. CSS禁止鼠标事件---pointer-events:none

    pointer-events:none顾名思意,就是鼠标事件拜拜的意思.元素应用了该CSS属性,链接啊,点击啊什么的都变成了“浮云牌酱油”.

  5. bzoj 3158 千钧一发 —— 最小割

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3158 \( a[i] \) 是奇数则满足条件1,是偶数则显然满足条件2: 因为如果把两个奇数 ...

  6. poj 2187 Beauty Contest —— 旋转卡壳

    题目:http://poj.org/problem?id=2187 学习资料:https://blog.csdn.net/wang_heng199/article/details/74477738 h ...

  7. nginx中给目录增加密码保护实现程序

    一款nginx中给目录增加密码保护实现程序,可以有效的保护一些目录不被访问,有需要的朋友可参考一下. 了防止一些可能出现存在漏洞的后台脚本暴露,使用验证的方式保护这些文件所在的目录 使用apache的 ...

  8. PCB设计基础及技巧

    一.设计步骤 (1)PCB布局 先放置接口类外设: 根据飞线的接口方向,定位各个模块的方位: 局部模块化(按照一个方向逐个局部化): (2)PCB布线 设置设计规则: 先布过孔(电源.地.长线),防止 ...

  9. AngularJs(Part 6)

    Overcomming same-origin policy restrictions with JSONP. AJAX has a restriction that it can only retr ...

  10. R: factor & list 生成和操作因子、列表

    ################################################### 问题:生成.操作列表 & 因子   18.4.27 怎么生成列表 list.因子 fac ...