目录
备忘录模式(memento pattern)定义:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
备忘录模式提供了一种对象状态的撤销实现机制,当系统中某一个对象需要恢复到某一历史状态时可以使用备忘录模式进行设计。
很多软件都提供了撤销(Undo)操作,如 Word、记事本、Photoshop、IDEA等软件在编辑时按 Ctrl+Z 组合键时能撤销当前操作,使文档恢复到之前的状态;还有在 浏览器 中的后退键、数据库事务管理中的回滚操作、玩游戏时的中间结果存档功能、数据库与操作系统的备份操作、棋类游戏中的悔棋功能等都属于这类。
备忘录模式的主要角色如下:
下面我们再来看看 UML 对应的代码实现。首先,我们创建原始对象Originator,对象中有四个属性,分别是 state 用于显示当前对象状态,id、name、phone 用来模拟业务属性,并添加 get、set 方法、create() 方法用于创建备份对象,restore(memento) 用于恢复对象状态。
package main.java.cn.test.memento.V1;
/**
* @author ningzhaosheng
* @date 2024/1/15 17:05:02
* @description 发起人类
*/
public class Originator {
private String state = "原始对象";
private String id;
private String name;
private String phone;
public Originator() {
}
//创建备忘录对象
public Memento create() {
return new Memento(id, name, phone);
}
//恢复对象状态
public void restore(Memento m) {
this.state = m.getState();
this.id = m.getId();
this.name = m.getName();
this.phone = m.getPhone();
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Originator{" +
"state='" + state + '\'' +
", id='" + id + '\'' +
", name='" + name + '\'' +
", phone='" + phone + '\'' +
'}';
}
}
package main.java.cn.test.memento.V1;
/**
* @author ningzhaosheng
* @date 2024/1/15 17:06:11
* @description备忘录对象 访问权限为: 默认,也就是同包下可见(保证只有发起者类可以访问备忘录类)
*/
public class Memento {
private String state = "从备份对象恢复为原始对象";
private String id;
private String name;
public Memento() {
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
private String phone;
public Memento(String id, String name, String phone) {
this.id = id;
this.name = name;
this.phone = phone;
}
}
package main.java.cn.test.memento.V1;
/**
* @author ningzhaosheng
* @date 2024/1/15 17:08:16
* @description 负责人类-保存备忘录对象
*/
public class Caretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
package main.java.cn.test.memento.V1;
/**
* @author ningzhaosheng
* @date 2024/1/15 17:08:48
* @description 测试类
*/
public class Test {
public static void main(String[] args) {
//创建发起人对象
Originator originator = new Originator();
originator.setId("1");
originator.setName("spike");
originator.setPhone("13512341234");
System.out.println("=============" + originator);
//创建负责人对象,并保存备忘录对象
Caretaker caretaker = new Caretaker();
caretaker.setMemento(originator.create());
//修改
originator.setName("update");
System.out.println("=============" + originator);
//从负责人对象中获取备忘录对象,实现撤销
originator.restore(caretaker.getMemento());
System.out.println("=============" + originator);
}
}
设计一个收集水果和获取金钱数的掷骰子游戏,游戏规则如下:
package main.java.cn.test.memento.V2;
import java.util.ArrayList;
import java.util.List;
/**
* @author ningzhaosheng
* @date 2024/1/15 17:12:51
* @description 表示玩家的状态
*/
public class Memento {
//所持金钱
int money;
//获得的水果
ArrayList fruits;
//构造函数
Memento(int money) {
this.money = money;
this.fruits = new ArrayList();
}
//获取当前玩家所有的金钱
int getMoney() {
return money;
}
//获取当前玩家所有的水果
List getFruits() {
return (List) fruits.clone();
}
//添加水果
void addFruit(String fruit) {
fruits.add(fruit);
}
}
package main.java.cn.test.memento.V2;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* @author ningzhaosheng
* @date 2024/1/15 17:13:55
* @description 玩家类
* 只要玩家的金币还够,就会一直进行游戏,在该类中会设置一个
* createMemento方法,其作用是保存当前玩家状态.还会包含一个restore撤
* 销方法,相当于复活操作。
*/
public class Player {
//所持金钱
private int money;
//获得的水果
private List<String> fruits = new ArrayList();
//随机数对象
private Random random = new Random();
//表示水果种类的数组
private static String[] fruitsName = {
"苹果", "葡萄", "香蕉", "橘子"
};
//构造方法
public Player(int money) {
this.money = money;
}
//获取当前所持有的金钱
public int getMoney() {
return money;
}
//获取一个水果
public String getFruit() {
String prefix = "";
if (random.nextBoolean()) {
prefix = "好吃的";
}
//从数组中获取水果
String f = fruitsName[random.nextInt(fruitsName.length)];
return prefix + f;
}
//掷骰子游戏
public void yacht() {
//掷骰子
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 fruit = getFruit();
System.out.println("获得了水果: " + fruit);
fruits.add(fruit);
} else {
//骰子结果为3、4、5
System.out.println("无效数字,继续投掷");
}
}
//拍摄快照
public Memento createMemento() {
Memento memento = new Memento(money);
for (String fruit : fruits) {
if (fruit.startsWith("好吃的")) {
memento.addFruit(fruit);
}
}
return memento;
}
//撤销方法
public void restore(Memento memento) {
this.money = memento.money;
this.fruits = memento.getFruits();
}
@Override
public String toString() {
return "Player{" + "money=" + money + ", fruits=" + fruits + '}';
}
}
package main.java.cn.test.memento.V2;
/**
* @author ningzhaosheng
* @date 2024/1/15 17:17:47
* @description 测试类
* 由于引入了备忘录模式,可以保存某个时间点的玩家状态,这样就可以对
* 玩家进行复活操作
*/
public class Test {
public static void main(String[] args) throws InterruptedException {
//最初所持的金钱数
Player player = new Player(100);
//保存最初状态
Memento memento = player.createMemento();
for (int i = 0; i < 100; i++) {
//显示扔骰子的次数
System.out.println("扔骰子的次数: " + (i+1));
//显示当前状态
System.out.println("当前状态: " + player);
//开启游戏
player.yacht();
System.out.println("所持有的金钱为: " + player.getMoney() + " 元");
//决定如何操作Memento
if (player.getMoney() > memento.getMoney()) {
System.out.println("赚到金币,保存当前状态,继续游戏!");
memento = player.createMemento();
} else if (player.getMoney() < memento.getMoney() / 2) {
System.out.println("所持金币不多了,将游戏恢复到初始状态!");
player.restore(memento);
}
Thread.sleep(1000);
System.out.println("");
}
}
}
好了,本次分享就到这里,欢迎大家继续阅读《设计模式》专栏其他设计模式内容,如果有帮助到大家,欢迎大家点赞+关注+收藏,有疑问也欢迎大家评论留言!