读《研磨设计模式》-代码笔记-备忘录模式-Memento

[b]声明:
本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客[url]http://chjavach.iteye.com/[/url][/b]


import java.util.ArrayList;
import java.util.List;


/*
* 备忘录模式的功能是,在不破坏封装性的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态,为以后的状态恢复作“备忘”
* 书上给了一个场景,仿真系统:
* 这个系统有两步操作,第一步操作后,产生一个临时数据(中间数据);
* 接下来的第二步操作有两种方案,这两种方案都要基于第一步产生的数据作进一步处理
* 不用备忘录模式的处理方法是:
* “客户端”调用时,自行创建一个变量来存储该对象第一步操作产生的临时数据,
* 在第二步操作进行之前,把临时数据再set回到该对象
* 这就把实现细节暴露到“客户端”去了
* 看书看到这里时,我想,既然是两步操作共存临时数据又不想暴露给外部,可以用内部类来保存这些数据。接着看下去,果然是这样
* 另外,为达到“在对象之外保存这个状态”,书上的例子是把“备忘录”作为“备忘录管理者”的类成员来达到这个目的
* 在“仿真系统”这个例子,似乎不需要“在对象之外保存这个状态”
*/

//不用模式的实现
class WorkflowA {

private String workflowName; //工作流名字
private int tempResult; //临时计算结果
private String tempState; //临时状态

public WorkflowA(String workflowName) {
this.workflowName = workflowName;
}

public void stepOne() {
this.tempResult = 1;
this.tempState = "State of stepOne.";
}

public void stepTwoSchema1() {
this.tempResult += 21;
this.tempState += "--> State of stepTwo by schema1.";
System.out.println(this.workflowName + " Schema1. result = " + this.tempResult + " state = " + this.tempState);
}

public void stepTwoSchema2() {
this.tempResult += 22;
this.tempState += "--> State of stepTwo by schema2.";
System.out.println(this.workflowName + " Schema2. result = " + this.tempResult + " state = " + this.tempState);
}

public int getTempResult() {
return tempResult;
}
public void setTempResult(int tempResult) {
this.tempResult = tempResult;
}
public String getTempState() {
return tempState;
}
public void setTempState(String tempState) {
this.tempState = tempState;
}

public String getWorkflowName() {
return workflowName;
}
}


//使用备忘录模式

//备忘录。是一个“窄接口”,空接口
interface IMemento {}

/*
* WorkflowB在业务逻辑上是和WorkflowA一样的,但增加了备忘录
* 这里为了偷懒,直接extends WorkflowA了,实际应用中不应该这样
*/
class WorkflowB extends WorkflowA implements Cloneable{

public WorkflowB(String workflowName) {
super(workflowName);
}

public IMemento createMemento() {
return new MementoImpl(this.getTempResult(), this.getTempState());
}

//备忘录
private static class MementoImpl implements IMemento {

private int tempResult;
private String tempState;

MementoImpl(int tempResult, String tempState) {
this.tempResult = tempResult;
this.tempState = tempState;
}

//提供get方法就好了
public int getTempResult() {
return tempResult;
}

public String getTempState() {
return tempState;
}
}

//恢复数据到“临时状态”-执行了第一步操作之后
public void setMemento(IMemento memento) {
MementoImpl mementoo = (MementoImpl)memento;
this.setTempResult(mementoo.getTempResult());
this.setTempState(mementoo.getTempState());
}
}


//结合原型模式(Prototype)
class WorkflowC extends WorkflowA implements Cloneable{

public WorkflowC(String workflowName) {
super(workflowName);
}

public IMemento createMemento() {
try {
return new MementoImpl((WorkflowC) this.clone()); //实际应用中要注意浅克隆的问题
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}

public void setMemento(IMemento memento) {
MementoImpl mementoo = (MementoImpl)memento;
this.setTempResult(mementoo.getWorkflow().getTempResult());
this.setTempState(mementoo.getWorkflow().getTempState());
}

private static class MementoImpl implements IMemento {

private WorkflowC workflow;

public MementoImpl(WorkflowC workflow) {
this.workflow = workflow;
}

public WorkflowC getWorkflow() {
return workflow;
}

}

}
//备忘录管理者 持有了备忘录对象,可把备忘录对象保存到想保存的地方,例如后面提到的保存到xml文件中
class CareTaker {

private IMemento memento;

public void saveMemento(IMemento memento) {
this.memento = memento; //这里可以保存到其他地方去,例如写到文件中
}

public IMemento retriveMemento() {
return this.memento; //如果是保存到文件中了,这里就是读文件
}
}


//扩展:使用备忘录模式来实现可撤销的操作。可与命令模式的实现作对比
interface ICommand {

public void execute();

public void undo(IMemento memento);

public void redo(IMemento memento);

public IMemento createMemento();

}


interface IOperation {

public int getResult();

public void add(int num); //加上num

public void substract(int num); //减去num

public IMemento createMemento();

public void setMemento(IMemento memento);

}


//将Command的一些公共操作提取到抽象的父类中去
abstract class AbstractCommand implements ICommand {

protected IOperation operation;

public void setOperation(IOperation operation) {
this.operation = operation;
}

public IMemento createMemento() {
return this.operation.createMemento();
}

//不管是撤销操作还是恢复操作,实际都是从备忘录中恢复到指定的状态
public void redo(IMemento memento) {
this.operation.setMemento(memento);
}

public void undo(IMemento memento) {
this.operation.setMemento(memento);
}

//具体是什么操作,交由子类来实现
public abstract void execute();
}


class AddCommand extends AbstractCommand {

private int num; //加数,增量

public void execute() {
this.operation.add(num);
}

public AddCommand(int num) {
this.num = num;
}
}


class SubstractCommand extends AbstractCommand {

private int num; //减数

public void execute() {
this.operation.substract(num);
}

public SubstractCommand(int num) {
this.num = num;
}
}


class Operation implements IOperation {

private int result; //被加数 or 被减数

public void add(int num) {
this.result += num;
}

public void substract(int num) {
this.result -= num;
}

public IMemento createMemento() {
return new Memento(this.result);
}

public int getResult() {
return result;
}

public void setMemento(IMemento memento) {
Memento mementoo = (Memento)memento;
this.result = mementoo.getResult();
}

private static class Memento implements IMemento {

public Memento(int result) {
this.result = result;
}

private int result;

public int getResult() {
return result;
}

public void setResult(int result) {
this.result = result;
}

}
}


class Caculator {

private List<ICommand> undoCmds = new ArrayList<ICommand>();

private List<ICommand> redoCmds = new ArrayList<ICommand>();

//IMemento[2]:两个Memento,一个是操作前,一个是操作后
private List<IMemento[]> undoMementos = new ArrayList<IMemento[]>();

private List<IMemento[]> redoMementos = new ArrayList<IMemento[]>();

private ICommand addCommand;

private ICommand substractCommand;

public void addPressed() {
IMemento mementoBefore = addCommand.createMemento();
addCommand.execute();
undoCmds.add(addCommand);
IMemento mementoAfter = addCommand.createMemento();
undoMementos.add(new IMemento[]{mementoBefore, mementoAfter});
}

public void substractPressed() {
IMemento mementoBefore = addCommand.createMemento();
substractCommand.execute();
undoCmds.add(substractCommand);
IMemento mementoAfter = substractCommand.createMemento();
undoMementos.add(new IMemento[]{mementoBefore, mementoAfter});
}

public void undoPress() {
if (undoCmds.size() > 0) {
ICommand cmd = undoCmds.get(undoCmds.size() - 1);
IMemento[] mementos = undoMementos.get(undoMementos.size() - 1);
cmd.undo(mementos[0]);

redoCmds.add(cmd);
redoMementos.add(mementos);

undoCmds.remove(cmd);
undoMementos.remove(mementos);
} else {
System.out.println("没有可撤销的命令");
}
}

public void redoPressed() {
if (redoCmds.size() > 0) {
ICommand cmd = redoCmds.get(redoCmds.size() - 1);
IMemento[] mementos = redoMementos.get(redoMementos.size() - 1);
cmd.redo(mementos[1]);

undoCmds.add(cmd);
undoMementos.add(mementos);

redoCmds.remove(cmd);
redoMementos.remove(mementos);
} else {
System.out.println("没有可恢复的命令");
}
}

public void setAddCommand(ICommand addCommand) {
this.addCommand = addCommand;
}

public void setSubstractCommand(ICommand substractCommand) {
this.substractCommand = substractCommand;
}


}


//这个类是用来测试的
public class MementoPattern {

public static void main(String[] args) {
//测试不使用模式
WorkflowA flow = new WorkflowA("WorkflowA");
flow.stepOne();
//下面两句是客户端在调用时作备份,将WorkflowA的实现细节暴露给客户端了
int tempResult = flow.getTempResult();
String tempState = flow.getTempState();
flow.stepTwoSchema1();
flow.setTempResult(tempResult);
flow.setTempState(tempState);
flow.stepTwoSchema2();

//测试使用备忘录模式
WorkflowB flowB = new WorkflowB("WorkflowB");
flowB.stepOne();
//保存“临时状态”
IMemento memento = flowB.createMemento();
CareTaker taker = new CareTaker();
taker.saveMemento(memento);
flowB.stepTwoSchema1();
//恢复到“临时状态”
flowB.setMemento(taker.retriveMemento());
flowB.stepTwoSchema2();

//测试使用备忘录模式与原型模式结合
WorkflowC flowC = new WorkflowC("WorkflowC");
flowC.stepOne();
//保存“临时状态”
memento = flowC.createMemento();
taker = new CareTaker();
taker.saveMemento(memento);
flowC.stepTwoSchema1();
//恢复到“临时状态”
flowC.setMemento(taker.retriveMemento());
flowC.stepTwoSchema2();

//测试备忘录模式结合命令模式实现可撤销的操作
IOperation operation = new Operation();
AddCommand addCommand = new AddCommand(5);
SubstractCommand substractCommand = new SubstractCommand(3);
addCommand.setOperation(operation);
substractCommand.setOperation(operation);

Caculator caculator = new Caculator();
caculator.setAddCommand(addCommand);
caculator.setSubstractCommand(substractCommand);

caculator.addPressed();
System.out.println("一次加法(加5)操作后的结果是:" + operation.getResult());

caculator.substractPressed();
System.out.println("一次减法(减3)操作后的结果是:" + operation.getResult());

caculator.undoPress();
System.out.println("撤销一次操作后的结果是:" + operation.getResult());

caculator.undoPress();
System.out.println("再撤销一次操作后的结果是:" + operation.getResult());

caculator.redoPressed();
System.out.println("恢复一次操作的结果是:" + operation.getResult());

caculator.redoPressed();
System.out.println("再恢复一次操作的结果是:" + operation.getResult());


}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值