您的位置:首页 > 编程语言 > Java开发

设计模式-备忘录模式(Memento)的详解

2017-07-04 18:25 369 查看

介绍

关于Java设计模式我们都知道有一种备忘录模式,对于作用看名字大概就知道应该和状态保存有关。本文就从定义到示例代码进行说明详解。

定义

备忘录模式定义:在不破坏封装性的前提下,捕获对象的内部状态。

本质:保存和恢复内部状态

作用:在不暴露内部状态不破坏封装完整性的前提下,能够统一的得到内部状态,并且在恰当的时机恢复内部状态。

内部状态

在一个java类里面,不可避免的需要保存一些数据(除非是一个纯静态方法构成的工具类或者其他)。因为这些内部状态很关键,比如一个内部状态是该类某个功能程序分支执行的关键值。

备忘录对象

因为内部状态在某些情况下又可能丢失(如内存紧张),就需要引入一些保存机制(如序列化然后以文件形式持久化保存)。针对复杂或者多个的数据值,我们就会封装数据对象,这个就是备忘录对象,为了让外部无法访问备忘录对象的值(即类的内部状态值),我们就会使用私有内部类,然后只暴露一个备忘录对象的访问方法。实现封装。同时这个备忘录对象是由外部负责保存,为了统一访问就需要标识类,也因为需要避免外部通过标识类访问到内部数据,备忘录模式就引入窄接口,一个空接口形式定义的标识类。这样就同时实现了统一访问和避免外部访问内部数据。

示例代码

以上就是对于备忘录模式的一些文字说明,以下代码基于上文的考虑,实现备忘录模式,并贴出使用代码。

先给出各个模块的名称和定义:

Memento:备忘录,它两个定义形式,窄接口定义:用于统一标识备忘录数据类。内部类的实现形式定义:具体的存储数据形式,它决定保存那些内部数据,因为定义在原发器内可以直接访问原发器内部数据。

Originator:原发器,可以使用备忘录保存某个瞬间的自身状态,也可以使用备忘录恢复内部状态。

Caretaker:备忘录管理者,主要负责对备忘录对象的保存,但是因为封装它不能对备忘录的具体内容进行操作和检查。

Memento窄接口

/**
* Created by LiCola on 2017/7/4.
* 备忘录 窄接口
* 用于对类型的标记
*/
public interface Memento {

}


Originator原发器

/**
* Created by LiCola on 2017/7/4.
* 原发器
* 持有内部状态 以及一些方法操作等
* 实现备忘录数据封装 提供内部状态的封装实现功能 、从外部恢复内部数据功能
*/
public class Originator {

/**
* 需要保存的 内部状态
*/
private String status;

/**
* 运行方法 修改内部状态
*/
public void doSomething(){
status="run";
}

/**
* 创建基于窄接口的内部类
* 并保存内部状态到内部类
* @return
*/
public Memento createMemento() {
MementoImpl memento = new MementoImpl();
memento.status = status;//保存操作
return memento;
}

/**
* 从外部 恢复内部状态
* @param memento
*/
public void setMemento(Memento memento) {
if (memento instanceof MementoImpl) {
status = ((MementoImpl) memento).status;//恢复操作
}
}

@Override
public String toString() {
return "Originator{" +
"status='" + status + '\'' +
'}';
}

/**
* 窄接口的内部实现类
*/
private static class MementoImpl implements Memento {

/**
* 使用默认修饰符
* 简化数据的set和get方法
*/
String status;

public MementoImpl() {
}
}
}


Catetaker备忘录管理者

/**
* Created by LiCola on 2017/7/4.
* 备忘录管理者
* 实现对备忘录窄接口实现类的保存和恢复
*/
public class Caretaker {

/**
* 为示例简单 只以内存形式保存
*/
private Memento memento;

/**
* 保存到内存
* @param memento
*/
public void saveMemento(Memento memento) {
this.memento = memento;
}

/**
* 从内存中恢复数据
* @return
*/
public Memento retriveMemento() {
return memento;
}

}


使用示例

/**
* Created by LiCola on 2017/7/4.
* 备忘录使用示例
*/
public class MementoClient {

public static void main(String[] args) {
Originator originator = new Originator();
originator.doSomething();//使用对象 做了一些操作

Caretaker caretaker = new Caretaker();
caretaker.saveMemento(originator.createMemento());//保存原发器某个瞬间状态

//假设被置空 回收了
originator = null;

Originator originatorRebuild = new Originator();//创建新的对象

originatorRebuild.setMemento(caretaker.retriveMemento());//从管理器中恢复保存状态

System.out.println(originatorRebuild.toString());//输出 "Originator{status='run'}"表示成功恢复内部状态

}
}


总结

备忘录的关键

我们首先要清楚的知道,备忘录的关键在于得到某个对象的内部状态,并暴露一个隐藏内部实现的窄接口,并由外部管理器负责数据的保存。每个模块功能清晰且互相关联。

备忘录模式还包含了,内部类和外部类访问,类型转换等Java语法。

备忘录的广义定义

上文实现代码是为了更好的示例,很多时候在实际的使用中对每个模块不会这么明晰的定义,比如备忘录管理者是被广义的定义在某个类之中,某个类集成了备忘录管理者的功能,而标识类(窄接口)内部也会有一些方法或者直接就是其他接口的形式定义(如
Parcelable
可以逻辑上定义为标识类)。我们学习设计模式是在学习的它的设计思想而不必拘泥一个具体形式。所以我认为备忘录模式更像是一种方法论一种看问题的方法。

备忘录的优点缺点

优点:在项目或框架中,备忘录模式封装的原发器的内部数据的保存和恢复操作,规范外部的访问和能够让外部能够统一的处理,同时也简化了操作,并明晰的定义各个模块的职责。使得代码逻辑清晰。

缺点:如果非要说的就是内存的开销,因为每一个瞬间内部状态保存都创建了一个对应的备忘录对象,频繁的操作是有内存开销的。

备忘录模式的使用

关于本文备忘录模式的讲解是为Android开发中Activity、Fragment、View等组件状态的保存和恢复操作的理解基础。在Android开发中关于以上组件状态保存是基础也是学习源码的关键。

参考

研磨设计模式
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息