图解设计模式 - Memento 模式

读书笔记 仅供参考

简述

Memento,备忘录模式,主要用于 Undo, Redo,History,Snapshot 等功能。事先将某个时间点的实例的状态保持下来,之后再有必要时,再将实例恢复至当时的状态。

角色和 UML

Originator

在保存自己的最新状态时生成 Memento 角色。当把以前的 Memento 角色传给 Originator 时,会自动恢复。

Memento

将 Originator 角色的内部信息整合在一起。
角色拥有以下两种接口(API):

  • wide interface :所有用于获取恢复对象状态信息的方法的集合。只有 Originator 可以使用。
  • narrow interface:获取有限的内部信息。
Caretaker

当 Caretaker 角色想要保存当前 Originator 角色时,通知 Originator 角色,Originator 再生成 Memento 角色返回给 Caretaker。Caretaker 只能使用 narrow interface。

UML

这里写图片描述

例子

例程是一个掷骰子游戏的程序,不同的点数会发生加钱,减钱,增加水果等情况,如果发现钱减少太多了,就回复上一次保存的状态。

// 记录主人公的状态
public class Memento {
    int money;
    ArrayList<String> fruits;

    Memento(int money) {
        this.money = money;
        fruits = new ArrayList<>();
    }

    void addFruits(String fruit) {
        fruits.add(fruit);
    }

    public int getMoney() {
        return money;
    }

   List<String> getFruits() {
        return (List<String>) fruits.clone();
    }
}
// 表示游戏主人公
public class Gamer {
    private int money; //所持金钱
    private List<String> fruits = new ArrayList<>();    //所获得的水果
    private Random random = new Random();   //随机数生成器
    private static String[] fruitsName = {
            "苹果", "葡萄", "香蕉", "橘子",
    };

    public Gamer(int money) {
        this.money = money;
    }

    public int getMoney() {
        return money;
    }

    // 掷筛子进行游戏
    public void bet() {
        int dice = random.nextInt(6) + 1;
        if (dice == 1) { //结果为一,增加金钱
            money += 100;
            System.out.println("金钱增加了");
        } else if (dice == 2) {
            money /= 2;
            System.out.println("金钱减半");
        } else if (dice == 6) {
            String f = getFruit();
            System.out.println("获得水果(" + f + ")");
        } else {
            System.out.println("什么都没有发生");
        }

    }
    // 拍摄快照
    public Memento createMemento() {
        Memento m = new Memento(money);
        Iterator<String> it = fruits.iterator();
        while (it.hasNext()) {
            String f = it.next();
            if (f.startsWith("好吃的")) {
                m.addFruits(f);
            }
        }
        return m;
    }
    // 撤销
    public void restoreMemento(Memento memento ) {
        this.money = memento.money;
        this.fruits = memento.fruits;
    }

    @Override
    public String toString() {
        return "Gamer{" +
                "money=" + money +
                ", fruits=" + fruits +
                ", random=" + random +
                '}';
    }
    private String getFruit() {
        String prefix = "";
        if(random.nextBoolean()) {
            prefix = "好吃的";
        }
        return prefix + fruitsName[random.nextInt(fruitsName.length)];
    }
}
public class Main {
    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) {

            }
            System.out.println();
        }
    }
}
结果

这里写图片描述

要点

  • 为了实现两套接口,可以利用 Java 的可见性
  • 可以使用多个 Memento
  • 注意 Memento 的有效期
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值