前言
- 说起备忘录模式也许会很陌生,但是我们身边有很多备忘录模式的应用,例如在手机或电脑上下棋,如果下错了,是可以悔棋的,在比如我们小时候玩坦克大战,如果坦克还有很多条命,而且现在装备很厉害,我们就想做一下备份,等挂掉的时候重新恢复一下接着打。这样我们就明白备忘录模式是做什么的了,简单说就是备份当前角色状态,后期可以回滚回来。
- 作为行为型模式的一种,备忘录模式并不是很有名,但是挺有用,备忘录模式实现方式 如果细分也有些差异,就像工厂模式一样,不过今天我举最简单的例子,用来说明备忘录模式是做什么的,而不再分析备忘录几种实现模式的差异(其实就是封装好不好的问题)。
- 本文中我先引入例子分析备忘录模式是怎么工作的,然后在总结一下它的特点,文末对程序在稍作改进分析。
情景引入
以上文的坦克大战为例,我坦克大战玩了几关后,好不容易攒了五条命,而且现在装备的是双发炮弹为了这次能通关,我就先把我的当前状态做了备份,实例如下
备忘录模式的三种角色
发起人(Originator) |
要备份的成员,里面提供了创建和恢复备忘录的方法(TankWarOriginator) |
备忘录(Memento) |
用来存储和获取发起人的状态(TankWarMemento) |
管理角色(Caretaker) |
用来管理备忘录(CareTaker) |
程序类图
java源程序
发起人
package memento;
public class TankWarOriginator {
int life;//有几条命
String state;//坦克装备
public TankWarOriginator(int life, String state) {
this.life = life;
this.state = state;
}
public void getCurrentState() {// 显示塔克当前状态
System.out.println("剩余" + life + "条命," + "炮弹状态为" + state);
}
/**
* 模拟玩家玩游戏,抛出异常是由于线程休眠的缘故,可以忽略
*
* @throws InterruptedException
*/
public void play() throws InterruptedException {
System.out.println("开始战斗.......");
Thread.sleep(3000);
life = life - 1;
state = "单发炮弹";
System.out.println("你被击中了,剩余" + life + "条命," + "炮弹变为" + state);
}
/*
* 创建备份
*/
public TankWarMemento createMemento() throws InterruptedException {
System.out.println("正在存储当前状态....");
Thread.sleep(4000);
TankWarMemento twm = new TankWarMemento(life, state);
System.out.println("存储完成");
return twm;
}
/*
* 恢复备份
*/
public void restore(TankWarMemento twm) throws InterruptedException {
System.out.println("正在恢复存档....");
life = twm.getLife();
state = twm.getState();
Thread.sleep(4000);
System.out.println("恢复完成");
}
public int getLife() {
return life;
}
public void setLife(int life) {
this.life = life;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
管理者
package memento;
public class CareTaker {
/*
* 专门用来管理备忘录对象的类
*/
TankWarMemento twm;
public TankWarMemento getTwm() {
return twm;
}
public void setTwm(TankWarMemento twm) {
this.twm = twm;
}
}
备忘录
package memento;
public class TankWarMemento{
/*
* 可以看出这是发起人里面状态的复制版
* 因此可以存储需要备份的状态
*/
int life;
String state;
public TankWarMemento(int life,String state) {
this.life=life;
this.state=state;
}
public int getLife() {
return life;
}
public void setLife(int life) {
this.life = life;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
客户端
package memento;
public class Client {
public static void main(String[] args) throws InterruptedException {
//初始化坦克状态
TankWarOriginator two=new TankWarOriginator(5, "双发炮弹");
CareTaker ct=new CareTaker();
two.getCurrentState();
ct.setTwm(two.createMemento());//管理者创建备份
two.play();
two.restore(ct.getTwm());//恢复备份
two.getCurrentState();
}
}
运行结果
程序分析
- 从程序中我们很明显看出备忘录结构上还是比较简单的,而且逻辑处理主要是在发起人里,备忘录里有和发起人相同的属性,这是因为他的存在就是为了备份,所以他要保存拷贝的值。
- 发起人角色负责了备忘录的创建与恢复,仔细看看应该不难理解。
- 程序里很多方法抛出异常,是由于我设置了线程休眠来模拟操作的过程,可以忽略,或者把线程休眠部分删去这样就不用抛出了。
既然已经看过了备忘录模式的例子,下面我们就总结一下它的一些特点吧。
备忘录模式的作用
在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
应用场景
已经很明显了,当你程序想引入撤销(回滚)功能的话,建立备忘录就行了(记得其实命令模式里好像也支持撤销操作,有兴趣的可以对比一下)。
状态模式优点
- 保持关键对象的数据封装
- 提供了恢复原有状态的的方法
缺点
- 应用该模式会占用较多的系统资源
- 存储和恢复过程比较耗时
备忘录模式就介绍到这里吧,下面我再尝试改变一下程序
既然状态属性发起人保存的有,而备忘录保存的也是一样的,不如提取出来,这样就避免了代码重写(个人感觉,我不确定提取出来好不好)
创建 公共的抽象类
package memento;
public abstract class AbstractState {
int life;
String state;
public AbstractState(int life,String state) {
this.life=life;
this.state=state;
}
public int getLife() {
return life;
}
public void setLife(int life) {
this.life = life;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
修改发起人类
package memento;
public class TankWarOriginator extends AbstractState{
public TankWarOriginator(int life, String state) {
super(life, state);
}
public void getCurrentState() {// 显示塔克当前状态
System.out.println("剩余" + life + "条命," + "炮弹状态为" + state);
}
/**
* 模拟玩家玩游戏,抛出异常是由于线程休眠的缘故,可以忽略
*
* @throws InterruptedException
*/
public void play() throws InterruptedException {
System.out.println("开始战斗.......");
Thread.sleep(3000);
life = life - 1;
state = "单发炮弹";
System.out.println("你被击中了,剩余" + life + "条命," + "炮弹变为" + state);
}
/*
* 创建备份
*/
public TankWarMemento createMemento() throws InterruptedException {
System.out.println("正在存储当前状态....");
Thread.sleep(4000);
TankWarMemento twm = new TankWarMemento(life, state);
System.out.println("存储完成");
return twm;
}
/*
* 恢复备份
*/
public void restore(TankWarMemento twm) throws InterruptedException {
System.out.println("正在恢复存档....");
life = twm.getLife();
state = twm.getState();
Thread.sleep(4000);
System.out.println("恢复完成");
}
}
修改备忘录类
package memento;
public class TankWarMemento extends AbstractState{
public TankWarMemento(int life, String state) {
super(life, state);
}
}