JavaMemento模式

本文最后更新于:10 个月前

保存对象状态

1 - 表示Gamer状态的类

public class Memento {
    int money;  // 所持金钱
    ArrayList fruits;   // 获得的水果

    public int getMoney() { // 获取当前所持有的金钱(narrow interface)
        return money;
    }

    Memento(int money) {    // 构造函数
        this.money = money;
        this.fruits = new ArrayList();
    }

    void addFruits(String fruit) {  // 添加水果
        fruits.add(fruit);
    }

    List getFruits() {  // 获取当前所持有的所有水果(wide interface)
        return (List)fruits.clone();
    }
}

2 - 表示游戏主人公的类.它会生成Memento的实例

public class Gamer {
    private int money;  //  所持金钱
    private List 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;   // 骰子结果为1时,增加所持有的金钱.
        if(dice == 1) {
            money += 100;
            System.out.println("所持金钱增加了.");
        } else if (dice == 2) { // 骰子结果为2时,所持金钱减半.
            money /= 2;
            System.out.println("所持金钱减半了.");
        } else if (dice == 6) { // 骰子结果为6时,获得水果
            String f = getFruit();
            System.out.println("获得了水果 (" + f + ").");
            fruits.add(f);
        } else {    // 骰子结果为3,4,5则什么都不会发生
            System.out.println("什么都没有发生");
        }
    }

    public Memento createMemento() {    // 拍摄快照
        Memento m = new Memento(money);
        for (Object fruit : fruits) {
            String f = (String) fruit;
            if (f.startsWith("好吃的")) {  // 只保存好吃的水果
                m.addFruits((String) f);
            }
        }
        return m;
    }

    public void restoreMemento(Memento memento) {   // 撤销
        this.money = memento.money;
        this.fruits = memento.getFruits();
    }

    @Override
    public String toString() {
        return "[money = " + money + ",fruits = " + fruits + "]";
    }

    private String getFruit() {
        String prefix = "";
        if (random.nextBoolean()) {
            prefix = "好吃的";
        }
        return prefix + fruitsName[random.nextInt(fruitsName.length)];
    }
}

3 - 进行游戏的类.它会事先保存Memento的实例, 之后会根据需要恢复Gamer的状态

public class Main {
    public static void main(String[] args) {
        Gamer gamer = new Gamer(100);   // 最初的金钱数为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() + "元");
            // 决定如何处理Memento
            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 ignored) {
            }
            System.out.println("");
        }
    }
}

4 - 输出示例

===0
当前状态: [money = 100,fruits = []]
什么都没有发生
所持金钱为100元

===1
当前状态: [money = 100,fruits = []]
所持金钱减半了.
所持金钱为50元

===2
当前状态: [money = 50,fruits = []]
什么都没有发生
所持金钱为50元

===3
当前状态: [money = 50,fruits = []]
所持金钱增加了.
所持金钱为150元
    (所持金钱增加了许多,因此保存游戏当前的状态)

===4
当前状态: [money = 150,fruits = []]
所持金钱增加了.
所持金钱为250元
    (所持金钱增加了许多,因此保存游戏当前的状态)

===5
当前状态: [money = 250,fruits = []]
什么都没有发生
所持金钱为250元

===6
当前状态: [money = 250,fruits = []]
什么都没有发生
所持金钱为250元

===7
当前状态: [money = 250,fruits = []]
所持金钱减半了.
所持金钱为125元

===8
当前状态: [money = 125,fruits = []]
获得了水果(好吃的苹果).
所持金钱为125元

===9
当前状态: [money = 125,fruits = [好吃的苹果]]
什么都没有发生
所持金钱为125元

===10
当前状态: [money = 125,fruits = [好吃的苹果]]
所持金钱减半了.
所持金钱为62元
(所持金钱减少了许多,因此将游戏恢复至以前的状态)

省略
===49
当前状态: [money = 525,fruits = [好吃的橘子, 橘子]]
什么都没有发生
所持金钱为525元

===50
当前状态: [money = 525,fruits = [好吃的橘子, 橘子]]
所持金钱减半了.
所持金钱为262元
(所持金钱减少了许多,因此将游戏恢复至以前的状态)

===51

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!