存档!-Memento模式

132 阅读1分钟

1、引入

许多玩过游戏的朋友知道,有些游戏有种堪称bug的功能-存档,在遇到不顺情况时可以重新读取存档,返回先前存档的时间点重新来过。

而Memento模式正是一种可以实现存档的设计模式。

2、示例

设计以下一款游戏:

  • 游戏者会投骰子,当投到1时金钱加100,2时金钱减一半,6时获得道具水果,其他什么都不会发生。
  • 然而我们的游戏者却采取“卑鄙”的策略,当他的金钱增加时会存档,大量减少时会重新读档。

2.1、存档类Memento

public class Memento {
    int money;
    ArrayList fruits;

    public int getMoney() {
        return money;
    }

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

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

    List getFruit() {
        return fruits;
    }
}

2.2、游戏类Gamer

public class Gamer {
    private int money;
    private List fruits=new ArrayList();
    private Random random=new Random();
    private static String[] fruitName={"苹果","葡萄","香蕉","橘子"};

    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("所持金钱增加100.");
        } else if (dice == 2) {
            money/=2;
            System.out.println("所持金钱减半.");
        } else if (dice == 6) {
            String f = getFruit();
            System.out.println("获得水果(" + f + ").");
            fruits.add(f);
        } else {
            System.out.println("什么事都没有发生");
        }
    }
    //存档
    public Memento createMemento() {
        Memento m=new Memento(money);
        Iterator iterator = fruits.iterator();
        while (iterator.hasNext()) {
            String f=(String) iterator.next();
            if (f.startsWith("好吃的")) {
                m.addFruit(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+fruitName[random.nextInt(fruitName.length)];
    }
}

2.3、测试

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);
            }
        }
    }
}

运行结果(部分):

image.png

3、tips

  • 这里实现的存档功能较为简单,应用上的存档功能往往涉及到IO以及一定存储格式
  • 应用Memento模式,可以实现
    • Undo
    • Redo
    • History
    • SnapShot