开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第33天,点击查看活动详情
备忘录模式
我们在使用文本编辑器编写文件时,如果不小心删除了某句话,可以通过撤销(undo )功能将文件恢复至之前的状态。有些文本编辑器甚至支持多次撤销,能够恢复至很久之前的版本。
使用面向对象编程的方式实现撤销功能时,需要事先保存实例的相关状态信息。然后,在撤销时,还需要根据所保存的信息将实例恢复至原来的状态。
事例程序
- 游戏是自动进行的
- 游戏的主人公通过掷骰子来决定下一个状态
- 当骰子点数为1的时候,主人公的金钱会增加
- 当骰子点数为2的时候,主人公的金钱会减少
- 当骰子点数为6的时候,主人公会得到水果
- 主人公没有钱时游戏就会结束
在程序中,如果金钱增加,为了方便将来恢复状态,我们会生成Memento类的实例,将现在的状态保存起来。所保存的数据为当前持有的金钱和水果。如果不断掷出了会导致金钱减少的点数,为了防止金钱变为0而结束游戏,我们会使用Memento的实例将游戏恢复至之前的状态。
类的一览表
| 名字 | 说明 |
|---|---|
| Memento | game的状态类 |
| Gamer | 游戏的主人公 |
| Main | 测试 |
类图
代码
Memento
- money表示主人公现在所持有的金钱数目,fruits表示现在为止所获得的水果。
public class Memento {
int money;//所持金钱
ArrayList<String> fruits;//所获得水果
public int getMoney() {
return money;
}
Memento(int money) {
this.money = money;
this.fruits = new ArrayList<>();
}
//添加水果
void addFruit(String fruit) {
fruits.add(fruit);
}
//获取所有水果
List getFruit() {
return (List) fruits.clone();
}
}
Gamer
Gamer类是表示游戏主人公的类。它有3个子段,即所持金钱(money)获得的水果(fruits )以及一个随机数生成器(random)。而且还有一个名为fruitsname 的静态字段。
- bet:,只要主人公没有破产,就会一直掷骰子,并根据骰子结果改变所持有的金钱数目和水果个数。
- createMemento方法的作用是保存当前的状态(拍摄快照)。在createMemento方法中,会根据当前在时间点所持有的金钱和水果生成一个Memento类的实例,该实例代表了“当前Gamer的状态”,它会被返回给调用者。(只保存好吃的水果)
- restoreMemento方法的功能与createMemento相反,它会根据接收到的Memento类的实例来将Gamer恢复为以前的状态
public class Gamer {
private int money;
private List<String> 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("所持金钱增加了");
} else if (dice == 2) {
//减半
money /= 2;
System.out.println("所持金钱减半");
} else if (dice == 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);
Iterator<String> it = fruits.iterator();
while (it.hasNext()) {
String f = it.next();
//保存好吃的水果
if (f.startsWith("好吃的")) {
m.addFruit(f);
}
}
return m;
}
//撤销
public void restoreMemento(Memento memento) {
this.money = memento.money;
this.fruits = memento.getFruit();
}
@Override
public String toString() {
return "money = " + money + " fruits = " + fruits;
}
//获得水果
private String getFruit() {
String prefix = "";
if (random.nextBoolean()) {
prefix = "好吃的";
}
return prefix + fruitName[random.nextInt(fruitName.length)];
}
}
Main
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) {
e.printStackTrace();
}
}
}
}