1.什么是备忘录模式?
备忘录模式:在不破坏封装的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
说人话:游戏存档,或者ctrl+Z的撤回操作
备忘录模式是一种对象行为型模式,其别名为标记模式。
2.备忘录结构
(1)Originator(原发器):原发器是一个普通类,它通过创建一个备忘录来存储当前内部状态,也可以使用备忘录来恢复其内部状态,一般将系统中需要保存内部状态的类设计为原发器
(2)Memento(备忘录):备忘录用于存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用,原发器的设计在不同的编程语言中实现机制会有所不同
(3)Caretaker(负责人):负责人又称为管理者,它负责保存备忘录,但是不能对备忘录的内容进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,它只负责存储对象,而不能修改对象,也无需知道对象的实现细节。
3.备忘录实现
(1)原发器
/**
* 原发器
*/
public class Originator {
private String state;
public Originator(String state){
this.state = state;
}
//创建一个备忘录对象
public Memento createMemento(){
return new Memento(this);
}
//根据备忘录对象恢复原发器状态
public void restoreMemento(Memento m){
state = m.state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
(2)备忘录类,默认可见性,包内可见
/**
* 备忘录类,默认可见性,包内可见
*/
class Memento {
public String state;
public Memento(Originator o){
state = o.getState();
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
(3)负责人类
/**
* 负责人类
*/
public class Caretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
(4)客户端类
public class Client {
public static void main(String[] args) {
//创建原发器对象
Originator ori = new Originator("状态(1)");
System.out.println(ori.getState());
//创建负责人对象,保存创建的备忘录对象
Caretaker ct = new Caretaker();
ct.setMemento(ori.createMemento());
ori.setState("状态(2)");
System.out.println(ori.getState());
//从负责人对象中取出备忘录对象,实现撤销
ori.restoreMemento(ct.getMemento());
System.out.println(ori.getState());
}
}
(5)结果及路径
4.备忘录实例——象棋悔棋的功能实现
(1)象棋棋子类,充当原发器
/**
* 象棋棋子类,充当原发器
*/
public class Chessman {
private String label;
private int x;
private int y;
public Chessman(String label,int x,int y){
this.label = label;
this.x = x;
this.y = y;
}
//保存状态
public ChessmanMemento save(){
return new ChessmanMemento(this.label,this.x,this.y);
}
//恢复状态
public void restore(ChessmanMemento memento){
this.label = memento.getLabel();
this.x = memento.getX();
this.y = memento.getY();
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
(2)象棋棋子备忘录类,充当备忘录
/**
* 象棋棋子备忘录类,充当备忘录
*/
class ChessmanMemento {
private String label;
private int x;
private int y;
public ChessmanMemento(String label,int x,int y){
this.label = label;
this.x = x;
this.y = y;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
(3)象棋棋子备忘录管理类,充当负责人
/**
* 象棋棋子备忘录管理类,充当负责人
*/
public class MementoCaretaker {
private ChessmanMemento memento;
public ChessmanMemento getMemento() {
return memento;
}
public void setMemento(ChessmanMemento memento) {
this.memento = memento;
}
}
(4)客户端
public class Client {
public static void main(String[] args) {
MementoCaretaker mc = new MementoCaretaker();
Chessman chess = new Chessman("车",1,1);
display(chess);
mc.setMemento(chess.save());//保存状态
chess.setY(4);
display(chess);
mc.setMemento(chess.save());//保存状态
chess.setX(5);
display(chess);
System.out.println("----------悔棋-------------");
chess.restore(mc.getMemento());//恢复状态
display(chess);
}
public static void display(Chessman chess) {
System.out.println("棋子"+chess.getLabel()+"当前位置为:第"+chess.getX()+"行,第"+chess.getY()+"列");
}
}
(5)运行结果及路径
5.象棋例子——实现多次撤销
(1)象棋棋子类,充当原发器
/**
* 象棋棋子类,充当原发器
*/
public class Chessman {
private String label;
private int x;
private int y;
public Chessman(String label,int x,int y){
this.label = label;
this.x = x;
this.y = y;
}
//保存状态
public ChessmanMemento save(){
return new ChessmanMemento(this.label,this.x,this.y);
}
//恢复状态
public void restore(ChessmanMemento memento){
this.label = memento.getLabel();
this.x = memento.getX();
this.y = memento.getY();
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
(2)象棋棋子备忘录类,充当备忘录
/**
* 象棋棋子备忘录类,充当备忘录
*/
class ChessmanMemento {
private String label;
private int x;
private int y;
public ChessmanMemento(String label,int x,int y){
this.label = label;
this.x = x;
this.y = y;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
(3)象棋棋子备忘录管理类,充当负责人
/**
* 象棋棋子备忘录管理类,充当负责人
*/
public class MementoCaretaker {
//定义一个集合来存储多个备忘录
private ArrayList mementoArrayList = new ArrayList();
public ChessmanMemento getMemento(int i) {
return (ChessmanMemento)mementoArrayList.get(i);
}
public void setMemento(ChessmanMemento memento){
mementoArrayList.add(memento);
}
}
(4)客户端
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.setX(4);
play(chess);
chess.setY(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()+"列");
}
}
6.备忘录优缺点
优:
(1)实现了状态恢复的实现机制
(2)实现对信息的封装,一个备忘录对象是一种原发器对象状态的标识
缺:
资源消耗过大
7.使用环境
(1)保存一个对象在某个时刻的状态,以后能随时恢复
(2)防止外界对象破坏一个对象历史状态的封装性