Memento模式(备忘录设计模式)

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方法
     */

    /**
     * 保存
     */

    /**
     * 恢复
     */

}

原文地址:https://www.cnblogs.com/dgwblog/p/9873969.html

时间: 2024-08-29 01:47:32

Memento模式(备忘录设计模式)的相关文章

设计模式(31)-----行为型模式-----备忘录设计模式

备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象.备忘录模式属于行为型模式. 介绍 意图:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态. 主要解决:所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态. 何时使用:很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"

备忘录设计模式

备忘录模式 备忘录设计模式将一个对象的内部状态进行捕捉并外部化,换句话说就是你将你的东西保存在某个地方.以后这个外部话的转台不需要借助封装就可以被回复,也就是私有的数据还是私有的. 如何使用备忘录设计模式 接下来将下面两个方法添加在ViewController.m中 - (void)saveCurrentState       {           [[NSUserDefaultsstandardUserDefaults] setInteger:currentAlbumIndexforKey:

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

一. 备忘录模式 定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 结构图: 使用范围: Memento 模式比较适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性中的一小部分时,Originator 可以根据保存的 Memento 信息还原到前一状态. 代码: [cpp] view plaincopy //备忘录类 //负责存储 Originator 对象的内部状态 class Meme

Java 实现备忘录(Memento)模式

/** * 数据对象 * @author stone * */ public class DataState { private String action; public void setAction(String action) { this.action = action; } public String getAction() { return action; } } /** * 一个保存另外一个对象内部状态拷贝 的对象.这样以后就可以将该对象恢复到原先保存的状态. * * @autho

Memento模式详解--设计模式(16)

Memento模式来源:      我们在进行软件系统的设计时候是要给用户后悔的权利(实际上可能也是用户要求的权利:)),我们对一些关键性的操作肯定需要提供诸如撤销(Undo)的操作.那这个后悔药就是Memento模式提供的. Memento模式作用:       在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态. Memento模式UML结构图如图1所示:                       Memento模式构成:

设计模式之Memento模式

备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可以将该对象恢复到原先保存的状态. 适用场合:比较适合用于功能比较复杂,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性中的一小部分时. 首先定义一个Originator(发起人)类 public class Originator { private String state;//需要保存的属性(可以定义多个) public void setState(String state){ th

Java备忘录模式(Memento模式)

Memento定义:memento是一个保存另外一个对象内部状态拷贝的对象,这样以后就可以将该对象恢复到原先保存的状态. Memento模式相对也比较好理解,我们看下列代码: public class Originator { private int number; private File file = null; public Originator(){} // 创建一个Memento public Memento getMemento(){ return new Memento(this)

【行为型】Memento模式

备忘录模式顾名思义就是一种能有备忘作用的设计模式,其目的是在对象外部保存其在某一时刻的状态信息,并且在任何需要的时候,都可以通过备忘录中保存的状态数据恢复对象在当时情形下的状态. 备忘录模式旨在对象的外部保存其状态.因此,对于备忘录对象将会有一个维护者 MementoManager 对象,用于维护对象所对应的所有备忘录对象列表,并在适当的时候需要负责清除掉这些备忘录对象.模式的类结构图参考如下: 模式的编码结构代码参考如下: 1 namespace memento 2 { 3 typedef i

Behavioral模式之Memento模式

1.意图 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的状态. 2.别名 Token 3.动机 有时候有必要记录一个对象的内部状态.为了允许用户取消不确定的操作或从错误中恢复过来,需要实现检查点和取消机制,而要实现这些机制,你必须事先将状态信息保存在某处,这样才能是对象恢复到他们先前的状态. 4.适用性 以下情况使用Memento模式: 必需保存一个对象在某一时刻的(部分)状态,这样以后需要时它能恢复到先前的状态. 如果一个用接口