设计模式入门——备忘录模式

本文通过坦克大战游戏实例,详细介绍了备忘录模式的工作原理及其应用场景。备忘录模式允许在不破坏封装的前提下,捕获并保存对象的内部状态,以便在需要时恢复到之前的状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

  1. 说起备忘录模式也许会很陌生,但是我们身边有很多备忘录模式的应用,例如在手机或电脑上下棋,如果下错了,是可以悔棋的,在比如我们小时候玩坦克大战,如果坦克还有很多条命,而且现在装备很厉害,我们就想做一下备份,等挂掉的时候重新恢复一下接着打。这样我们就明白备忘录模式是做什么的了,简单说就是备份当前角色状态,后期可以回滚回来。
  2. 作为行为型模式的一种,备忘录模式并不是很有名,但是挺有用,备忘录模式实现方式 如果细分也有些差异,就像工厂模式一样,不过今天我举最简单的例子,用来说明备忘录模式是做什么的,而不再分析备忘录几种实现模式的差异(其实就是封装好不好的问题)。
  3. 本文中我先引入例子分析备忘录模式是怎么工作的,然后在总结一下它的特点,文末对程序在稍作改进分析。

 

情景引入

      以上文的坦克大战为例,我坦克大战玩了几关后,好不容易攒了五条命,而且现在装备的是双发炮弹为了这次能通关,我就先把我的当前状态做了备份,实例如下

 

备忘录模式的三种角色

发起人(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();
	}

}

运行结果

 

程序分析

  1. 从程序中我们很明显看出备忘录结构上还是比较简单的,而且逻辑处理主要是在发起人里,备忘录里有和发起人相同的属性,这是因为他的存在就是为了备份,所以他要保存拷贝的值。
  2. 发起人角色负责了备忘录的创建与恢复,仔细看看应该不难理解。
  3. 程序里很多方法抛出异常,是由于我设置了线程休眠来模拟操作的过程,可以忽略,或者把线程休眠部分删去这样就不用抛出了。

 

既然已经看过了备忘录模式的例子,下面我们就总结一下它的一些特点吧。

备忘录模式的作用

       在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

 

应用场景

       已经很明显了,当你程序想引入撤销(回滚)功能的话,建立备忘录就行了(记得其实命令模式里好像也支持撤销操作,有兴趣的可以对比一下)。

 

状态模式优点

  1. 保持关键对象的数据封装
  2. 提供了恢复原有状态的的方法

 

缺点

  1. 应用该模式会占用较多的系统资源
  2. 存储和恢复过程比较耗时

 

备忘录模式就介绍到这里吧,下面我再尝试改变一下程序

      既然状态属性发起人保存的有,而备忘录保存的也是一样的,不如提取出来,这样就避免了代码重写(个人感觉,我不确定提取出来好不好)

创建 公共的抽象类

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值