备忘录模式
意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以后可将该对象恢复到原先保存的状态。顾名思义,就是提供备忘功能。
适用性
1、必须保存一个对象在摸一时刻的状态,便于后续对他的恢复
2、如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性
结构
Memento
备忘录存储原发器对象的内部状态。原发器根据需要决定备忘录存储原发器的哪些状态
防止原发器以外的其他对象访问备忘录。理想情况之允许生成本备忘录的那个原发器访问本备忘录的内部状态
Originator
原发器创建一个备忘录,用以记录当前时刻的内部装阿嚏
使用备忘录恢复内部状态
Caretaker
负责保存备忘录
不能对备忘录的内容进行操作或者检查
实现
实现就是一个简单的模拟游戏内存档的一个操作,恢复操作则是选择对应的存档进行恢复
package memento;
/**
* @Author fitz.bai
* @Date 2018/9/6 15:46
*/
public class Zhuxian {
private String state;
private double latitude;
private double longitude;
public Zhuxian(String state, double latitude, double longitude) {
this.state = state;
this.latitude = latitude;
this.longitude = longitude;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public ZhuxianMemento save() {
return new ZhuxianMemento(this.state, this.latitude, this.longitude);
}
public void restore(ZhuxianMemento zhuxianMemento) {
this.state = zhuxianMemento.getState();
this.latitude = zhuxianMemento.getLatitude();
this.longitude = zhuxianMemento.getLongitude();
}
}
package memento;
/**
* @Author fitz.bai
* @Date 2018/9/6 15:49
*/
public class ZhuxianMemento {
private String state;
private double latitude;
private double longitude;
public ZhuxianMemento(String state, double latitude, double longitude) {
this.state = state;
this.latitude = latitude;
this.longitude = longitude;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(int latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(int longitude) {
this.longitude = longitude;
}
}
package memento;
import java.util.ArrayList;
/**
* @Author fitz.bai
* @Date 2018/9/6 15:50
*/
public class MementoCaretaker {
private ArrayList mementoList = new ArrayList();
public ZhuxianMemento getMemento(int i) {
return (ZhuxianMemento) mementoList.get(i);
}
public void setMemento(ZhuxianMemento memento) {
mementoList.add(memento);
}
}
package memento;
/**
* @Author fitz.bai
* @Date 2018/9/6 15:46
*/
public class Client {
private static int index = -1;
private static MementoCaretaker mementoCaretaker = new MementoCaretaker();
public static void main(String[] args) {
// 初始位置
Zhuxian zhuxian = new Zhuxian("张小凡", 23.6, 54.6);
// 存个档
mementoCaretaker.setMemento(zhuxian.save());
display(zhuxian);
// 传送到别处
zhuxian.setLatitude(65.2);
// 存个档
mementoCaretaker.setMemento(zhuxian.save());
display(zhuxian);
// 再去往别处
zhuxian.setLatitude(125.2);
display(zhuxian);
// 打不过了,快回到出生地
zhuxian.restore(mementoCaretaker.getMemento(0));
display(zhuxian);
}
private static void display(Zhuxian zhuxian) {
System.out.println(zhuxian.getState() + "当前位置为:" + "经度" + zhuxian.getLatitude() + "," + "纬度" + zhuxian.getLongitude());
}
}
/**张小凡当前位置为:经度23.6,纬度54.6
张小凡当前位置为:经度65.2,纬度54.6
张小凡当前位置为:经度125.2,纬度54.6
=================回档==================
张小凡当前位置为:经度23.6,纬度54.6
*/
其实备忘录模式十分简单,可以简单理解为,你有一个对象A,你想保存一下他,就将你需要的属性值存储到另外一个对象B中,而在用一个管理对象B的对象C将对象B存储起来,等到需要的时候,再去对象C中找到对应的对象B,他就是你当时备忘起来的属性。
注意封装性
https://quanke.gitbooks.io/design-pattern-java
备忘录是一个很特殊的对象,只有原发器对它拥有控制的权力,负责人只负责管理,而其他类无法访问到备忘录,因此我们需要对备忘录进行封装。
为了实现对备忘录对象的封装,需要对备忘录的调用进行控制,对于原发器而言,它可以调用备忘录的所有信息,允许原发器访问返回到先前状态所需的所有数据;对于负责人而言,只负责备忘录的保存并将备忘录传递给其他对象;对于其他对象而言,只需要从负责人处取出备忘录对象并将原发器对象的状态恢复,而无须关心备忘录的保存细节。理想的情况是只允许生成该备忘录的那个原发器访问备忘录的内部状态。
在实际开发中,原发器与备忘录之间的关系是非常特殊的,它们要分享信息而不让其他类知道,实现的方法因编程语言的不同而有所差异,在C++中可以使用friend关键字,让原发器类和备忘录类成为友元类,互相之间可以访问对象的一些私有的属性;在Java语言中可以将原发器类和备忘录类放在一个包中,让它们之间满足默认的包内可见性,也可以将备忘录类作为原发器类的内部类,使得只有原发器才可以访问备忘录中的数据,其他对象都无法使用备忘录中的数据。
优点
1、它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原。
2、备忘录实现了对信息的封装,一个备忘录对象是一种原发器对象状态的表示,不会被其他代码所改动。备忘录保存了原发器的状态,采用列表、堆栈等集合来存储备忘录对象可以实现多次撤销操作。
缺点
1、资源消耗过大,如果需要保存的原发器类的成员变量太多,就不可避免需要占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源。