备忘录模式

1.备忘录模式是什么

1.百度百科

备忘录模式 (Memento Pattern):又叫做快照模式(Snapshot Pattern)或Token模式。在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

2.维基百科

The memento pattern is a software design pattern that provides the ability to restore an object to its previous state (undo via rollback).

The memento pattern is implemented with three objects: the originator, a caretaker and a memento. The originator is some object that has an internal state. The caretaker is going to do something to the originator, but wants to be able to undo the change. The caretaker first asks the originator for a memento object. Then it does whatever operation (or sequence of operations) it was going to do. To roll back to the state before the operations, it returns the memento object to the originator. The memento object itself is an opaque object (one which the caretaker cannot, or should not, change). When using this pattern, care should be taken if the originator may change other objects or resources - the memento pattern operates on a single object.

Classic examples of the memento pattern include the seed of a pseudorandom number generator (it will always produce the same sequence thereafter when initialized with the seed state)[citation needed][clarification needed] and the state in a finite state machine.

看到维基百科的解释我忍不住拍手称绝啊。 给一个对象提供一个能恢复以前状态的对象。

3.lz理解

玩过单机游戏的人都知道,其实这个设计模式说的就是一个存档、备份和还原也是这个道理、数据库中的回滚也是。

将某个对象某时的内部状态读取出来存储到另外一个对象中,以便于该对象出现问题时恢复该对象。

叫备忘录模式感觉并不合理叫存档模式感觉比较合理。

4.核心角色

备忘录(Memento)角色 :备忘录角色存储“备忘发起角色”的内部状态。“备忘发起角色”根据需要决定备忘录角色存储“备忘发起角色”的哪些内部状态。为了防止“备忘发起角色”以外的其他对象访问备忘录。备忘录实际上有两个接口,“备忘录管理者角色”只能看到备忘录提供的窄接口——对于备忘录角色中存放的属性是不可见的。“备忘发起角色”则能够看到一个宽接口——能够得到自己放入备忘录角色中属性。

备忘发起(Originator)角色 :“备忘发起角色”创建一个备忘录,用以记录当前时刻它的内部状态。在需要时使用备忘录恢复内部状态。

备忘录管理者(Caretaker)角色 :负责保存好备忘录。不能对备忘录的内容进行操作或检查。

2.备忘录模式解决了什么问题

状态保存 对象的内部状态保存在一个外部对象中,以便于恢复对象。

封装安全 不破坏对象的封装

3.备忘录模式用法

就拿程序员最熟悉的代码举例子吧。代码需要提交、撤销、回滚等操作。

备忘发起角色

/**
 * 当前编辑中的代码
 */
public class EditCode {

	private String code;

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public EditCode(String code) {
		this.code = code;
	}

	public SaveCode createSaveCode() {
		return new SaveCode(code);
	}

	public void restoreSaveCode(SaveCode saveCode) {
		this.code = saveCode.getCode();
	}

}

备忘录角色

/**
 * 存储的代码
 */
public  class SaveCode {

	private String code;

	public SaveCode(String code) {
		this.code = code;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

}

备忘管理者角色

public class SaveList {

	private List<SaveCode> codeList;

	public SaveList() {
		codeList = new ArrayList<SaveCode>();
	}

	public Integer setSaveCode(SaveCode saveCode) {
		codeList.add(saveCode);
		return codeList.indexOf(saveCode);

	}
	//这里可能出现越界的问题、暂不考虑
	public SaveCode getSaveCode(int index) {
		return codeList.get(index);
	}

}

客户端角色

public class Client {

	public static void main(String[] args) {
		//写代码
		EditCode ec =new EditCode("Hello");
		//存档
		SaveList sl = new SaveList();
		//存储的位置
		Integer index0 = sl.setSaveCode(ec.createSaveCode());
		System.out.println("备份完毕!位置是("+index0+") 内容是"+ec.getCode());
		ec.setCode(ec.getCode()+" World!");
		Integer index1 = sl.setSaveCode(ec.createSaveCode());
		System.out.println("备份完毕!位置是("+index1+") 内容是"+ec.getCode());
		ec.setCode(ec.getCode()+" Are you OK?");
		Integer index2 = sl.setSaveCode(ec.createSaveCode());
		System.out.println("备份完毕!位置是("+index2+") 内容是"+ec.getCode());
		//回滚操作
		System.out.println("----回滚("+index1+")代码----");
		ec.restoreSaveCode(sl.getSaveCode(index1));
		System.out.println("回滚完毕!内容是"+ec.getCode());
		//恢复操作
		System.out.println("----撤销("+index1+")回滚----");
		ec.restoreSaveCode(sl.getSaveCode(index2));
		System.out.println("撤销完毕!内容是"+ec.getCode());

	}
}

结果

备份完毕!位置是(0) 内容是Hello

备份完毕!位置是(1) 内容是Hello World!

备份完毕!位置是(2) 内容是Hello World! Are you OK?

----回滚(1)代码----

回滚完毕!内容是Hello World!

----撤销(1)回滚----

撤销完毕!内容是Hello World! Are you OK?

4.备忘录模式的问题

1、如果发起人角色的状态需要完整地存储到备忘录对象中,那么在资源消耗上面备忘录对象会很昂贵。
2、当负责人角色将一个备忘录 存储起来的时候,负责人可能并不知道这个状态会占用多大的存储空间,从而无法提醒用户一个操作是否很昂贵。
3、当发起人角色的状态改变的时候,有可能这个协议无效。如果状态改变的成功率不高的话,不如采取“假如”协议模式。

5.备忘录模式总结

使用场景:
1、需要保存/恢复数据的相关状态场景。
2、提供一个可回滚的操作。

碎碎念:
当看到这个模式的时候眼前一亮,这不就是存档么。原来这还是一种设计模式呢,其实很多设计模式我们天天都在使用只是不知道这个东西叫什么。在我看来学习设计模式并不只是学习其设计方式,更多的是学习一种解释能力,吧一系列特别复杂的概念解释为一个词。就像《盗梦空间》到底讲了个啥,对于程序员来说非常简单就能解释啊,不就是递归么。以后遇到这种带回滚操作的功能我们也能说这不就是备忘录模式嘛。

posted @ 2018-02-05 18:10  枫飘雪落  阅读(219)  评论(0编辑  收藏  举报