3)实现多次撤销
1.结构图
对负责人类MementoCaretaker进行了修改,在其中定义了一个ArrayList类型的集合对象来存储多个备忘录。
2.代码实现
import java.util.*;public class MementoCaretaker {//定义一个集合来存储多个备忘录private ArrayList mementolist = new ArrayList();public ChessmanMemento getMemento(int i) {return (ChessmanMemento)mementolist.get(i);}public void setMemento(ChessmanMemento memento) {mementolist.add(memento);}
}
客户端类
public class Client {private static int index = -1; //定义一个索引来记录当前状态所在位置private static MementoCaretaker mc = new MementoCaretaker();public static void main(String args[]) {Chessman chess = new Chessman("车",1,1);play(chess); chess.setY(4);play(chess);chess.setX(5);play(chess); undo(chess,index);undo(chess,index); redo(chess,index);redo(chess,index);}//下棋public static void play(Chessman chess) {//保存备忘录mc.setMemento(chess.save()); index++; System.out.println("棋子" + chess.getLabel() + "当前位置为:" + "第" + chess.getX() + "行" + "第" + chess.getY() + "列。");}//悔棋public static void undo(Chessman chess,int i) {System.out.println("******悔棋******");index--; chess.restore(mc.getMemento(i-1)); //撤销到上一个备忘录System.out.println("棋子" + chess.getLabel() + "当前位置为:" + "第" + chess.getX() + "行" + "第" + chess.getY() + "列。");}//撤销悔棋public static void redo(Chessman chess,int i) {System.out.println("******撤销悔棋******"); index ++; chess.restore(mc.getMemento(i+1)); //恢复到下一个备忘录System.out.println("棋子" + chess.getLabel() + "当前位置为:" + "第" + chess.getX() + "行" + "第" + chess.getY() + "列。");}
}
3.注意
本实例只能实现最简单的Undo和Redo操作,并未考虑对象状态在操作过程中出现分支的情况。
如果在撤销到某个历史状态之后,用户再修改对象状态,此后执行Undo操作时可能会发生对象状态错误,在实际开发中,可以使用链表或者堆栈来处理有分支的对象状态改变。
4)总结
备忘录是一个很特殊的对象,只有原发器对它拥有控制的权力,负责人只负责管理,而其他类无法访问到备忘录。
1.优点
-
它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤。
-
备忘录保存了原发器的状态,采用列表、堆栈等集合来存储备忘录对象可以实现多次撤销操作。
2.缺点
资源消耗过大,如果需要保存的原发器类的成员变量太多,就不可避免需要占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源。
3.适用场景
-
保存一个对象在某一个时刻的全部状态或部分状态,以后需要时能够恢复到先前的状态,实现撤销操作。
-
防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态的实现细节暴露给外界对象。