定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样就可以将该对象恢复到原先保存的状
态。
备忘录模式引入一个存储状态的备忘录对象,为了让外部无法访问这个对象的值,一般把这个对象实现成需要保存数据的对象的内部类,通常还是私有的,保证封装性不被破坏。但是这个备忘录对象需要存储在外部,所以要让备忘录对象实现一个窄接口,这个接口是空的,只是一个标识接口,什么方法都没有,从而保证了备忘录内的数据不会被外部获取或操作。
Memento:备忘录。主要用来存储原发器对象的内部状态。
Originator:原发器。需要备忘录对象保存其内部状态的对象。
Caretaker:备忘录管理者。主要是保存备忘录对象。
/**
* 备忘录的窄接口
*
*/
public interface Memento {
}
/**
* 原发器对象
*
*/
public class Originator {
/**
* 原发器的状态
*/
private String state = "";
/**
* 创建原发器的备忘录对象
* @return
*/
public Memento createMemento(){
return new MementoImpl(state);
}
/**
* 重新设置备忘录的对象,让他回到备忘录记录的状态
* @param memento
*/
public void setMemento(Memento memento){
MementoImpl mementoImpl = (MementoImpl)memento;
this.state = mementoImpl.getState();
}
/**
* 真正的备忘录对象,实现备忘录窄接口
* 实现成私有的,不让外部访问
*
*/
private static class MementoImpl implements Memento {
private String state = "";
public MementoImpl(String state){
this.state = state;
}
public String getState(){
return state;
}
}
}
/**
* 负责保存备忘录的对象
*
*/
public class Caretaker {
/**
* 备忘录对象
*/
private Memento memento = null;
/**
* 保存备忘录对象
* @param memento 要被保存的备忘录对象
*/
public void saveMemento(Memento memento) {
this.memento = memento;
}
/**
* 获取被保存的备忘录对象
* @return 被保存的备忘录对象
*/
public Memento retrieveMemento(){
return this.memento;
}
}
样例
/**
* 备忘录窄接口
*
*/
public interface FlowAMockMemento {
}
/**
* 原发器,模拟运行流程A
* @author joe
*
*/
public class FlowAMock {
/**
* 流程名
*/
private String flowName;
/**
* 外部需要的结果数据
*/
private int tempResult;
/**
* 需要外部存储的状态数据
*/
private String tempState;
public FlowAMock(String flowName) {
this.flowName = flowName;
}
/**
* 运行流程的第一阶段(前半部分)
*/
public void runPhaseOne(){
tempResult = 3;
tempState = "PhaseOne result";
}
/**
* 按照方案一来运行流程的后半部分
*/
public void schema1() {
System.out.println(this.tempState + " is " + tempResult);
this.tempResult += 11;
this.tempState = "Running Schema1 result";
System.out.println(this.tempState + " is " + tempResult);
}
/**
* 按照方案二来运行流程的后半部分
*/
public void schema2(){
System.out.println(this.tempState + " is " + tempResult);
this.tempResult += 22;
this.tempState = "Running Schema2 result";
System.out.println(this.tempState + " is " + tempResult);
}
/**
* 创建原发器的备忘录对象
* @return
*/
public FlowAMockMemento createMemento(){
return new MementoImpl(this.tempResult, this.tempState);
}
/**
* 重新设置原发器对象状态,让其回到备忘录对象记录的状态
* @param memento
*/
public void setMemento(FlowAMockMemento memento){
MementoImpl mementoImpl = (MementoImpl)memento;
this.tempResult = mementoImpl.getTempResult();
this.tempState = mementoImpl.getTempState();
}
/**
* 真正的备忘录对象,实现备忘录的窄接口
* 实现成私有的内部类,不让外部访问
*
*/
private static class MementoImpl implements FlowAMockMemento {
private int tempResult;
private String tempState;
public MementoImpl(int tempResult, String tempState) {
this.tempResult = tempResult;
this.tempState = tempState;
}
public int getTempResult() {
return tempResult;
}
public String getTempState() {
return tempState;
}
}
}
/**
* 保存模拟流程A对象的备忘录对象
*
*/
public class FlowAMementoCareTaker {
/**
* 模拟流程A对象的备忘录对象
*/
private FlowAMockMemento memento = null;
/**
* 保存备忘录对象
* @param memento
*/
public void saveMemento(FlowAMockMemento memento) {
this.memento = memento;
}
/**
* 获取被保存的备忘录对象
* @return
*/
public FlowAMockMemento retrieveMemento() {
return this.memento;
}
}
public class Client {
public static void main(String[] args) {
FlowAMock flowA = new FlowAMock("TestFlow");
flowA.runPhaseOne();
//创建此时的备忘录对象
FlowAMockMemento memento = flowA.createMemento();
//创建一个管理者
FlowAMementoCareTaker careTaker = new FlowAMementoCareTaker();
careTaker.saveMemento(memento);
flowA.schema1();
flowA.setMemento(careTaker.retrieveMemento());
//flowA.setMemento(memento);
flowA.schema2();
}
}
结合原型模式:如果原发器对象中全部或大部分的状态都需要保存,一个简洁的办法就是直接克隆一个原发器对象。也就是说这时备忘录对象中存放的是一个原发器对象的实例。
public class FlowAMock implements Cloneable{
/**
* 流程名
*/
private String flowName;
/**
* 外部需要的结果数据
*/
private int tempResult;
/**
* 需要外部存储的状态数据
*/
private String tempState;
public FlowAMock(String flowName) {
this.flowName = flowName;
}
/**
* 运行流程的第一阶段(前半部分)
*/
public void runPhaseOne(){
tempResult = 3;
tempState = "PhaseOne result";
}
/**
* 按照方案一来运行流程的后半部分
*/
public void schema1() {
System.out.println(this.tempState + " is " + tempResult);
this.tempResult += 11;
this.tempState = "Running Schema1 result";
System.out.println(this.tempState + " is " + tempResult);
}
/**
* 按照方案二来运行流程的后半部分
*/
public void schema2(){
System.out.println(this.tempState + " is " + tempResult);
this.tempResult += 22;
this.tempState = "Running Schema2 result";
System.out.println(this.tempState + " is " + tempResult);
}
public FlowAMockMemento createMemento(){
try {
return new MementoImpl((FlowAMock) this.clone());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
/**
* 设置原发器对象的状态,让其回到备忘录对象记录的状态
* @param memento
*/
public void setMemento(FlowAMockMemento memento) {
MementoImpl mementoImpl = (MementoImpl)memento;
this.tempResult = mementoImpl.getFlowAMock().tempResult;
this.tempState = mementoImpl.getFlowAMock().tempState;
}
private static class MementoImpl implements FlowAMockMemento{
private FlowAMock flowAMock = null;
public MementoImpl (FlowAMock flowAMock){
this.flowAMock = flowAMock;
}
public FlowAMock getFlowAMock(){
return flowAMock;
}
}
}
使用备忘录的潜在代价
标准的备忘录模式的实现机制是依靠缓存来实现的,因此,当需要备忘录的数据较大时,或者数量很多时,或者用户频繁第创建备忘录对象时,都会导致很大的开销。