1. Memento模式
使用面向对象编程方式实现撤销功能时,需要事先保存实例的相关状态信息。然后,在撤销时,还需要根据所保存的信息将实例恢复至原来的状态。
Memento的意思:“备忘录”、“纪念品”
其做的功能可能是:
- 撤销(Undo)
- 重做(Redo)
- 历史记录(History)
- 快照(Snapshot)
1.1 Memento模式的类图
登场角色:
-
Originator(生成者)
Originator就是需要被保存,被记录快照的对象。其含有生成Memento和恢复Memento的方式 -
Memento(纪念品)
Originator的快照 -
Caretaker(负责人)
Caretaker决定了在什么时候调用Originator的方法,即什么是时候调用Originator方法生成Memento的策略
1.2 示例程序
类一览表:
名字 | 说明 |
---|---|
Memento | 表示Gamer状态的类 |
Gamer | 一个游戏类 |
Main | 进行游戏,会调用Gamer的方式生成Memento |
uml类图
Memento类
package xin.ajay.memento;
import java.util.ArrayList;
import java.util.List;
public class Memento {
private int money;
private List<String> fruits = new ArrayList<>();
public int getMoney() {
return money;
}
public void addFruit(String fruit){
fruits.add(fruit);
}
public List<String> getFruits(){
return fruits;
}
public Memento(int money) {
this.money = money;
}
}
Gamer类
package xin.ajay.memento;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
public class Gamer {
/*
游戏规则:
玩家通过掷骰子决心下一个状态
点数为1 金钱增加
点数为2 金钱减少
点数为6 获得水果
当money为0时,游戏结束
*/
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 i = random.nextInt(6) + 1;
switch (i) {
case 1:
money += 100;
System.out.println("金钱增加了");
break;
case 2:
money /= 2;
System.out.println("金钱减少了");
break;
case 6:
String fruit = getFruit();
fruits.add(fruit);
System.out.println("获得水果(" + fruit + ")。");break;
default:
System.out.println("什么都没发生");
}
}
//拍摄快照
public Memento createMemento(){
Memento memento = new Memento(money);
//保存逻辑
for (String f : fruits) {
if (f.startsWith("好吃的")) {
memento.addFruit(f);
}
}
return memento;
}
private String getFruit() {
String prefix = "";
if (random.nextBoolean()) {
prefix = "好好的";
}
return prefix + fruitsname[random.nextInt(fruitsname.length)];
}
@Override
public String toString() {
return "Gamer{" + "money=" + money + ", fruits=" + fruits + '}';
}
public void restoreMemento(Memento memento) {
this.money = memento.getMoney();
this.fruits = memento.getFruits();
}
}
Main类
package xin.ajay.memento;
public class Main {
public static void main(String[] args) {
Gamer gamer = new Gamer(100);
Memento memento = gamer.createMemento();//保持状态
for (int i = 0; i < 10; 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(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
鸣谢:
GoF《设计模式》和结城浩的《图解设计模式》