`
guafei
  • 浏览: 329303 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

备忘录

阅读更多
备忘录(Memento Pattern)模式
备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式。

备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化
存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一同使用。

常见的软件系统往往不止存储一个状态,而是需要存储多个状态。这些状态常常是一个对象历史发展的不同阶段的快照,存储这些快照的备忘录对象
叫做此对象的历史,某一个快照所处的位置叫做检查点。

备忘录角色:
备忘录角色有如下的责任。
1、将发起人(Originator)对象的内部状态存储起来,备忘录可以根据发起人对象的判断来决定存储多少
     发起人(Originator)对象的内部状态。
2、备忘录可以保护其内容不被发起人对象之外的任何对象所读取。备忘录有两个等效的接口:
1、窄接口:负责人(Caretaker)对象(和其他除发起人对象之外的任何对象)看到的是备忘录的窄
   接(narrow interface),这个窄接口只允许它把备忘录对象传给其他的对象;

2、宽接口:与负责人对象看到的窄接口相反的是,发起人对象可以看到一个宽接口(wide interface),
   这个宽接口允许它读取所有的数据,以便根据数据恢复这个发起人对象的内部状态。853P
  
发起人角色:
发起人角色有如下责任:
1、创建一个含有当前的内部状态的备忘录对象。
2、使用备忘录对象存储其内部状态。

负责人角色:
负责人角色有如下的责任:
1、负责保存备忘录对象
2、不检查备忘录对象的内容。

宽接口和白箱:
发起人角色
public class Originator{
private String state;

//工厂方法,返还一个新的备忘录对象
public Memento createMemento(){
return new Memento(state);
}

//将发起人恢复到备忘录对象所记载的状态
public void restoreMemento(Memento memento){
this.state = memento.getState();
}

//状态的取值方法
public String getState(){
return this.state;
}

//状态的赋值方法
public void setState(String state){
this.state = state;
System.out.println("Current state = " + this.state);
}
}

备忘录模式要求备忘录对象提供两个不同的接口:一个宽接口提供给发起人对象,另一个窄接口提供给所有其他的对象,包括负责人对象。
宽接口允许发起人读取到所有的数据;窄接口只允许它把备忘录对象传给其他的对象而看不到内部的数据。
//备忘录角色
public class Memento{
private String state;

public Memento(String state){
this.state = state;
}

public String getState(){
return this.state;
}

public void setState(String state){
this.state = state;
}
}

负责人角色负责保存备忘录对象,但是从不修改(甚至不查看)备忘录对象的内容(一个更好的实现是负责人对象根本无法从备忘录
对象中读取个修改其内容)

//负责人角色
public class Caretaker{
private Memento memento;

//备忘录的取值方法
public Memento retrieveMemento(){
return this.memento;
}

//备忘录的赋值方法
public void saveMemento(Memento memento){
this.memento = memento;
}
}

//客户端
public class Client{
private static Originator o = new Originator();
private static Caretaker c= new Caretaker();
private static void main(String[] args){
//该负责人对象的状态
o.setState("On");
//创建备忘录对象,并将发起人对象的状态存储起来
c.saveMemento(o.createMemento());
//修改发起人对象的状态
o.setState("Off");
//恢复发起人对象的状态
o.restoreMemento(c.retrieveMemento());
}
}
首先将发起人对象的状态设置成“On”(或者任何有效状态),并且创建一个备忘录对象将这个状态存储起来;然后将发起人对象
的状态改成“Off”(或者任何状态);最后又将发起人对象恢复到备忘录对象所存储起来的状态,即“On”状态(或者先前所
存储的任何状态)

备忘录系统运行的时序是这样的:
(1)将发起人对象的状态设置成“On”。
(2)调用发起人角色的createMemento()方法,创建一个备忘录对象将这个状态存储起来。
(3)将备忘录对象存储到负责人对象中去。
备忘录系统恢复的时序是这样的:
(1)将发起人对象的状态设置成“Off”;
(2)将备忘录对象从负责人对象中取出;
(3)将发起人对象恢复到备忘录对象所存储起来的状态,“On”状态。

白箱实现的优缺点
白箱实现的一个明显的好处是比较简单,因此常常用做教学目的。白箱实现的一个明显的缺点是破坏对发起人状态的封装。

窄接口或者黑箱实现
//发起人角色
public class Originator{
private String state;

public Originator(){
}

//工厂方法,返还一个新的备忘录对象
public MementoIF createMemento(){
return new Memento(this.state);
}

//将发起人恢复到备忘录对象记录的状态
public void restoreMemento(MementoIF memento){
Memento aMemento = (Memento)memento;
this.setState(aMemento.getState());
}

public String getState(){
return this.state;
}

public void setState(){
this.state = state;
System.out.println("state = " + state);
}

protected class Memento implements MementoIF{
private String savedState;
private Mememto(String someState){
savedState = someState;
}

private void setState(String someState){
savedState = someState;
}

private String getState(){
return savedState;
}
}
}

public interface MementoIF{}

public class Caretaker{
private MementoIF memento;

public MementoIF retrieveMemento(){
return this.memento;
}

public void saveMemento(MementoIF memento){
this.memento = memento;
}
}

public class Client{
private static Originator o = new Originator();
private static Caretaker c = new Caretaker();

public static void main(String args[]){
//改变负责人对象的状态
o.setState("On");
//创建备忘录对象,并将发起人对象的状态存储起来
c.saveMemento(o.createMemento());
//修改发起人对象的状态
o.setState("Off");
//恢复发起人对象的状态
o.restoreMemento(c.retrieveMemento());
}
}

黑箱实现运行时的时序为;
(1)将发起人对象的状态设置成“On”。
(2)调用发起人角色的 createMemento()方法,创建一个备忘录对象将这个状态存储起来。
(3)将备忘录对象存储到负责人对象中去。由于负责人对象拿到的仅是 MementoIF类型,因此无法读出备忘录内部的状态。
恢复时的时序为:
(1)将发起人对象的状态设置成“Off”;
(2)将备忘录对象从负责人对象中取出。注意此时仅能得到 MementoIF接口,因此无法读出此对象的内部状态
(3)将发起人对象的状态恢复成备忘录对象所存储起来的状态,,由于发起人对象的内部类Memento实现了MementoIF接口
     这个内部类是传入的备忘录对象的真实类型,因此发起人对象可以利用内部类Memento 的私有 接口读出此对象的内部状态
    
存储多个状态的备忘录模式:
//发起人角色
import java.util.Vector;
import java.util.Enumeration;

public class Originator{
private Vector states;
private int index;

public Originator(){
states = new Vector();
index = 0;
}

public Memento createMementor(){
return new Mementor(states,index);
}

public void restoreMementor(Mementor memento){
states = memento.getStates();
index = memento.getIndex();
}

public void setState(String state){
this.states.addElement(state);
index ++;
}

//辅助方法,打印出所有的状态
public void printStates(){
System.out.println("Total number of states: " + index);
for(Enumeration e = states.elements();e.hasMoreElements();){
system.out.println(e.nextElement());
}
}
}

//备忘录角色
import java.util.Vector;

public class Memento{
private Vector states;
private int index;

public Memento(Vector states,int index){
this.states = (Vector)states.clone();
this.index = index;
}

//状态取值方法
Vector getStates(){
return states;
}

//检查点取值方法
int getIndex(){
return this.index;
}
}
******************备忘录的构造子克隆了传入的states,然后将克隆存入到备忘录对象内部,这是一个重要的细节,因为不这样的话,将会
  将会造成客户端和备忘录对象持有对同一个Vector对象的引用,也可以同时修改这个Vector对象,会造成系统崩溃。
 
//负责人角色
import java.util.Vector;

public class Caretaker{
private Originator o;
private Vector mementos = new Vector();
private int current;

public Caretaker(Originator o){
this.o = o;
current = 0;
}

public int createMemento(){
Memento memento = o.createMemento();
mementos.addElement(memento);
return current ++;
}

//将发起人恢复到某个检查点
public void restoreMemento(int index){
Memento memento = (Memento)mementos.elementAt(index);
o.restoreMemento(memento);
}

//某个检查点删除
public void removeMemento(int index){
mementos.removeElementAt(index);
}
}

//客户端
public class Client{
private static Originator o = new Originator();
private static Caretaker c = new Caretaker(o);
public static void main(String[] args){
//改变状态
o.setState("state 0");
//建立一个检查点
c.createMemento();
//改变状态
o.setState("state 1");

c.createMemento();

o.setState("state 2");

c.createMemento();

o.setState("state 3");

c.createMemento();

o.setState("state 4");

c.createMemento();

o.printStates();

//恢复到第二个检查点
System.out.println("Restoring to 2");

c.restoreMemento(2);

o.printStates();

System.out.println("Restoring to 0");

c.restoreMemento(0);

o.printStates();

System.out.println("Restoring to 3");

c.restoreMemento(3);

o.printStates();


}
}

自述历史模式(备忘录模式的一个变种):
//窄接口
public interface MementoIF{}

//发起人角色
public class Originator{
public String state;

public Originator(){}

public void changeState(String state){
this.state = state;
System.out.println("State has been changed to : " + state);
}

public Memento createMemento(){
return new Memento(this);
}

public void restoreMemento(MementoIF memento){
Memento m = (Memento)memento;
changeState(m.state);
}

class Memento implements MementoIF{
private String state;

private String getState(){
return state;
}

private Memento(Originator o){
this.state = o.state;
}
}
}

//客户端
public class Client{
private static Originator o;
private static MementoIF memento;

public static void main(String args[]){
o = new Originator();
o.changeState("State 1");
memento = o.createMemento();
o.changeState("State 2");
o.restoreMemento(memento);
}
}


模式的优缺点:
由于“自述历史”作为一个备忘录模式的特殊实现形式非常简单易懂,它可能是备忘录模式最为流行的实现形式。

备忘录模式的操作过程
1、客户端为发起人角色创建一个备忘录对象。
2、调用发起人对象的某个操作,这个操作是可以撤销的。
3、检查发起人对象所出状态的有效性。检查的方式可以是发起人对象的内部自查,也可以由某个外部对象进行检查。
4、如果需要的话,将发起人的操作撤销,也就是说根据备忘录对象的记录,将发起人对象的状态恢复过来。

“假如”协议模式的操作过程:
1、将发起人对象做一个拷贝。
2、在拷贝上执行某个操作。
3、检查这个拷贝的状态是否有效和自恰。
4、如果检查结果是无效或者不自恰的,那么扔掉这个拷贝,并触发异常处理程序;相反,如果检查是有效和自恰的,那么在原对象上执行这个操作
显然这一做法对于撤销一个操作并恢复操作前状态较为复杂和困难的发起人对象来说是一个较为谨慎和有效的做法。

“假如”协议模式的优点和缺点
具体来说,这个做法的长处是可以保证发起人对象永远不会处于无效或不自恰的状态上,这样作的短处是成功的操作必须执行两次。
如果操作的成功率较低的话,这样做就比较划算,反之就不太划算。


使用备忘录模式的优点和缺点

一、备忘录模式的优点
1、有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这时,
   使用备忘录模式可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以恰当地保持封装的边界。
2、本模式简化了发起人类。发起人不再需要管理和保存其内部状态的一个个版本,客户端可以自行管理他们所需
   要的这些状态的版本。
3、当发起人角色的状态改变的时候,有可能这个状态无效,这时候就可以使用暂时存储起来的备忘录将状态复原。
二、备忘录模式的缺点:
1、如果发起人角色的状态需要完整地存储到备忘录对象中,那么在资源消耗上面备忘录对象会很昂贵。
2、当负责人角色将一个备忘录 存储起来的时候,负责人可能并不知道这个状态会占用多大的存储空间,从而无法
   提醒用户一个操作是否很昂贵。882——P
3、当发起人角色的状态改变的时候,有可能这个协议无效。如果状态改变的成功率不高的话,不如采取“假如”协议模式。
分享到:
评论

相关推荐

    微信小程序 备忘录 (源码)

    微信小程序 备忘录 (源码)微信小程序 备忘录 (源码)微信小程序 备忘录 (源码)微信小程序 备忘录 (源码)微信小程序 备忘录 (源码)微信小程序 备忘录 (源码)微信小程序 备忘录 (源码)微信小程序 备忘录 (源码)微信小...

    小程序源码 备忘录 (代码+截图)

    小程序源码 备忘录 (代码+截图)小程序源码 备忘录 (代码+截图)小程序源码 备忘录 (代码+截图)小程序源码 备忘录 (代码+截图)小程序源码 备忘录 (代码+截图)小程序源码 备忘录 (代码+截图)小程序源码 备忘录 (代码+...

    微信小程序源码 备忘录(学习版)

    微信小程序源码 备忘录(学习版)微信小程序源码 备忘录(学习版)微信小程序源码 备忘录(学习版)微信小程序源码 备忘录(学习版)微信小程序源码 备忘录(学习版)微信小程序源码 备忘录(学习版)微信小程序源码 备忘录(学习...

    桌面备忘录(可放在桌面的备忘录)

    【标题】:“桌面备忘录(可放在桌面的备忘录)”是一款便捷的桌面工具,旨在帮助用户轻松记录日常生活和工作中的重要事项。这款备忘录软件设计精巧,可以直接放置在桌面上,便于随时查看和编辑,提高了工作效率与...

    微信小程序 小工具类 备忘录 (源代码+截图)

    微信小程序 小工具类 备忘录 (源代码+截图)微信小程序 小工具类 备忘录 (源代码+截图)微信小程序 小工具类 备忘录 (源代码+截图)微信小程序 小工具类 备忘录 (源代码+截图)微信小程序 小工具类 备忘录 (源...

    微信小程序-备忘录-记录代办事项(源码+截图)

    微信小程序实现的简易备忘录,可以记录代办事项,可以标记事项是否完成 微信小程序实现的简易备忘录,可以记录代办事项,可以标记事项是否完成 微信小程序实现的简易备忘录,可以记录代办事项,可以标记事项是否完成...

    Android 备忘录源码.rar

    《Android 备忘录应用开发详解》 在移动设备上,备忘录应用程序是一种非常实用的工具,它可以帮助用户记录日常琐事、待办事项或重要想法。Android平台提供了丰富的API和工具,使得开发者能够轻松构建这样的应用。...

    日历备忘录Java源码

    在本项目中,"日历备忘录Java源码" 提供了一套完整的日历应用程序的源代码,主要由四个核心文件组成:NotePad.java、CalendarPad.java、Month.java 和 Year.java。这些文件分别代表了备忘录、日历、月份和年份的功能...

    Android开发备忘录

    设计和实现一个类似个人备忘录的 Android APP ,数据库采用 SQLite (也可以直接访问 Web 端 MySQL 数据库、或提供 Web 接口访问 MySQL 数据库)。 1.用户注册和登录(这类 APP 一般面对个人,用户不需要分类别); ...

    Android程序研发源码Android 备忘录源码.zip

    在Android程序开发中,备忘录应用是一种常见的项目,它涉及到许多核心的Android技术知识点。这份"Android程序研发源码Android 备忘录源码.zip"包含了一个完整的备忘录应用的源代码,可以帮助开发者深入理解Android...

    Java日历及备忘录

    Java日历及备忘录程序是一个实用的桌面应用程序,它模仿了Windows操作系统中的日历功能,并添加了备忘录管理特性。这个程序的核心是利用Java编程语言实现的,旨在帮助用户方便地查看日期并设置提醒,提高个人或工作...

    Android课程设计--便捷备忘录

    **Android课程设计--便捷备忘录** 在移动应用开发领域,Android系统因其开源特性与广泛的应用,成为开发者的重要平台。本项目"Android课程设计--便捷备忘录"旨在教授学生如何利用Android Studio进行应用程序开发,...

    html制作的备忘录html制作的备忘录

    5. **交互元素**:备忘录通常需要用户输入,所以会使用`<form>`元素来创建表单,`<input>`定义输入字段,`<textarea>`用于多行文本输入,`<button>`创建按钮。通过`<label>`元素关联输入字段和文本,提升可读性和...

    备忘录系统(源码+项目说明).zip

    备忘录系统(源码+项目说明).zip备忘录系统(源码+项目说明).zip备忘录系统(源码+项目说明).zip备忘录系统(源码+项目说明).zip备忘录系统(源码+项目说明).zip备忘录系统(源码+项目说明).zip备忘录系统...

    易语言备忘录提醒源码.zip易语言项目例子源码下载

    易语言备忘录提醒源码是一个适用于学习和实践的项目示例,它可以帮助初学者和开发者理解如何使用易语言来创建具有提醒功能的备忘录应用。以下是关于这个项目的一些关键知识点和学习要点: 1. **事件驱动编程**:...

    软件实施备忘录.docx

    《软件实施备忘录》是一份详尽的指导文档,旨在帮助项目经理在IT行业中,特别是在管理软件实施领域,成功地进行项目管理和执行。备忘录强调了成为一个优秀的IT项目经理所必需的各种技能和知识,同时也提供了关于业务...

    C#自制桌面备忘录(自制日历)

    《C#自制桌面备忘录(自制日历)——打造个性化日程管理工具》 在IT行业中,开发一款个性化的桌面备忘录软件是提升工作效率和生活管理的重要手段。本项目名为"C#自制桌面备忘录(自制日历)",采用C#编程语言和...

    简易安卓备忘录

    【简易安卓备忘录】是一个基于Java编程语言开发的Android应用程序,主要功能是提供一个便捷的备忘录服务。这个项目对于初学者来说是一个很好的学习资源,它可以帮助理解Android应用的基本架构、Java语言在移动平台上...

    最好用的备忘录 桌面备忘录

    《桌面备忘录:高效管理日常事务的利器》 在我们的日常生活和工作中,常常需要记录各种琐碎但重要的事项,以便随时查阅和提醒。这时,一款好用的备忘录软件就显得尤为重要。"最好用的备忘录 桌面备忘录"就是这样一...

    android studio 简单备忘录

    在Android Studio中开发一个简单的备忘录应用是一个常见的任务,涉及到Android应用程序的基础架构、用户界面设计、数据存储以及事件处理等多个方面。以下是一些相关的知识点: 1. **Android Studio介绍**:Android ...

Global site tag (gtag.js) - Google Analytics