目录
1、场景直入与定义
我们都遇到过交换两个变量的值的场景:
int a=1234;
int b=3215;
如果要交换两个变量的值,需要有一个临时变量c当做过度:
int c=a;
a=b;
b=c;
临时变量c做了一个a值的保存,备忘录模式与这个思想差不多。你可以单独新建一个对象,用于保存另外一个对象的状态,然后可以用于备份与恢复。类似于“游戏存档存盘”、“word编辑回退”。当然保存的对象多了可以放到List或者栈里,进一步也可以序列化保存到磁盘上。
2、代码示例
假设,我在写一篇博客Article,写的过程中要保存或回退到上一个版本。版本保存用ArticleMemento,版本多了,统一放到栈里进行管理。
package behavioral.memento;
public class Article {
private String title;
private String content;
private String imgs;
public Article(String title, String content, String imgs) {
this.title = title;
this.content = content;
this.imgs = imgs;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getImgs() {
return imgs;
}
public void setImgs(String imgs) {
this.imgs = imgs;
}
public ArticleMemento saveToMemento() {
ArticleMemento articleMemento = new ArticleMemento(this.title,this.content,this.imgs);
return articleMemento;
}
public void undoFromMemento(ArticleMemento articleMemento) {
this.title = articleMemento.getTitle();
this.content = articleMemento.getContent();
this.imgs = articleMemento.getImgs();
}
@Override
public String toString() {
return "Article{" +
"title='" + title + '\'' +
", content='" + content + '\'' +
", imgs='" + imgs + '\'' +
'}';
}
}
package behavioral.memento;
public class ArticleMemento {
private String title;
private String content;
private String imgs;
public ArticleMemento(String title, String content, String imgs) {
this.title = title;
this.content = content;
this.imgs = imgs;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
public String getImgs() {
return imgs;
}
@Override
public String toString() {
return "ArticleMemento{" +
"title='" + title + '\'' +
", content='" + content + '\'' +
", imgs='" + imgs + '\'' +
'}';
}
}
package behavioral.memento;
public class Test {
public static void main(String[] args) {
ArticleMementoManager articleMementoManager = new ArticleMementoManager();
Article article= new Article("设计模式A","博客内容A","博客图片A");
ArticleMemento articleMemento = article.saveToMemento();
articleMementoManager.addMemento(articleMemento);
System.out.println("标题:"+article.getTitle()+" 内容:"+article.getContent()+" 图片:"+article.getImgs()+" 暂存成功");
System.out.println("博客完整信息:"+article);
System.out.println("修改博客start");
article.setTitle("设计模式B");
article.setContent("博客内容B");
article.setImgs("博客图片B");
System.out.println("修改博客end");
System.out.println("博客完整信息:"+article);
articleMemento = article.saveToMemento();
articleMementoManager.addMemento(articleMemento);
article.setTitle("设计模式C");
article.setContent("博客内容C");
article.setImgs("博客图片C");
System.out.println("暂存回退start");
System.out.println("回退出栈1次");
articleMemento = articleMementoManager.getMemento();
article.undoFromMemento(articleMemento);
System.out.println("回退出栈2次");
articleMemento = articleMementoManager.getMemento();
article.undoFromMemento(articleMemento);
System.out.println("暂存回退end");
System.out.println("博客完整信息:"+article);
}
}
3、序列化与反序列化
有些场景,仅仅存放在内存中的另一个对象中并不能满足我们的需求,可能是对象过大过多,太占内存,可能我们需要永久的保存下来,就像游戏存档,这就需要把对象进行序列化然后保存到文件实现持久化保存。
比如坦克大战游戏中,需要保存整体所有对象的当前状态,需要将所有游戏对象序列化到本地文件。前提是需要序列化的类需要实现Serializable接口。
public void save() {
File f=new File("d:/tank.data");
ObjectOutputStream ooStream=null;
try {
ooStream=new ObjectOutputStream(new FileOutputStream(f));
ooStream.writeObject(myTank);
ooStream.writeObject(objects);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if (ooStream!=null) {
try {
ooStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public void load() {
File f=new File("d:/tank.data");
ObjectInputStream oiStream=null;
try {
oiStream=new ObjectInputStream(new FileInputStream(f));
myTank=(Tank) oiStream.readObject();
objects=(List<GameObject>) oiStream.readObject();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
if (oiStream!=null) {
try {
oiStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
如果对象的某些属性不想被序列化,可以使用transient关键字屏蔽。
性能更好的序列化与反序列化考虑使用protobuf。