设计模式之禅之设计模式-备忘录模式

《一:备忘录模式的定义
        --->备忘录模式(Memento Pattern)提供了一种弥补真实世界缺陷的方法,让“后悔药”在程序的世界中真实可行
        --->在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
        --->通俗地说,备忘录模式就是一个对象的备份模式,提供了一种程序数据的备份方法

二:备忘录模式的角色

● Originator发起人角色
        记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和恢复备忘录数据。
● Memento备忘录角色
        负责存储Originator发起人对象的内部状态,在需要的时候提供发起人需要的内部状态。
● Caretaker备忘录管理员角色
        对备忘录进行管理、保存和提供备忘录。

三:备忘录模式的应用      
【1】备忘录模式使用场景  
        ● 需要保存和恢复数据的相关状态场景。
        ● 提供一个可回滚(rollback)的操作;比如Word中的CTRL+Z组合键,IE浏览器中的后退按钮,文件管理器上的backspace键等。
        ● 需要监控的副本场景中。
        ● 数据库连接的事务管理就是用的备忘录模式,想想看,如果你要实现一个JDBC驱动,你怎么来实现事务?还不是用备忘录模式嘛!

【2】备忘录模式的注意事项
        ● 备忘录的生命期
                备忘录创建出来就要在“最近”的代码中使用,要主动管理它的生命周期,建立就要使用,不使用就要立刻删除其引用,等待垃圾回收器对它的回收处理。
        ● 备忘录的性能
                不要在频繁建立备份的场景中使用备忘录模式(比如一个for循环中),原因有二:一是控制不了备忘录建立的对象数量;二是大对象的建立是要消耗资源的,系统的性能需要考虑。因此,如果出现这样的代码,设计师就应该好好想想怎么修改架构了。
 
【3】备忘录模式的最佳实践
        备忘录模式是我们设计上“月光宝盒”,可以让我们回到需要的年代;是程序数据的“后悔药”,吃了它就可以返回上一个状态;是设计人员的定心丸,确保即使在最坏的情况下也能获得最近的对象状态。如果大家看懂了的话,请各位在设计的时候就不要使用数据库的临时表作为缓存备份数据了,虽然是一个简单的办法,但是它加大了数据库操作的频繁度,把压力下放到数据库了,最好的解决办法就是使用备忘录模式。

四:备忘录模式的案例 

【1】简单备忘录模式的标准
《一》发起者

 1 package com.yeepay.sxf.template19;
 2 /**
 3  * 【简单标准的备忘录模式】的发起者
 4  * @author sxf
 5  *
 6  */
 7 public class Originator {
 8     //内部状态
 9     private String state="";
10
11     public String getState() {
12         return state;
13     }
14
15     public void setState(String state) {
16         this.state = state;
17     }
18
19     //创建一个备忘录
20     public  Memento createMemento(){
21         return new Memento(this.state);
22     }
23     //恢复一个备忘录
24     public void restoreMemento(Memento memento){
25         this.setState(memento.getState());
26     }
27
28 }

View Code

《二》备忘录

 1 package com.yeepay.sxf.template19;
 2 /**
 3  * 备忘录角色
 4  * @author sxf
 5  *
 6  */
 7 public class Memento {
 8     //发起人的内部状态
 9     private String state="";
10
11     public Memento(String _state){
12         this.state=_state;
13     }
14
15     public String getState() {
16         return state;
17     }
18
19     public void setState(String state) {
20         this.state = state;
21     }
22
23 }

View Code

《三》备忘录管理

 1 package com.yeepay.sxf.template19;
 2 /**
 3  * 备忘录的管理员角色
 4  * @author sxf
 5  *
 6  */
 7 public class Caretaker {
 8
 9     private Memento memento;
10
11     public Memento getMemento() {
12         return memento;
13     }
14
15     public void setMemento(Memento memento) {
16         this.memento = memento;
17     }
18
19
20 }

View Code

【2】基于克隆的备忘模式
《一》发起者

 1 package com.yeepay.sxf.template19;
 2 /**
 3  * 【结合原型模式的备忘录模式】
 4  * 使用Clone方式的备忘录模式,可以使用在比较简单的场景或者比较单一的场景
 5  * 中,尽量不要与其他的对象产生严重的耦合关系。
 6  * @author sxf
 7  *
 8  */
 9 public class Originatord implements Cloneable {
10     //内部备忘录
11     private Originatord originatord;
12
13     //初始化状态
14     private String state="";
15
16     //创建一个备忘录
17     public void createMemento(){
18         try {
19             Originatord dOriginatord=this.clone();
20             this.originatord=dOriginatord;
21         } catch (CloneNotSupportedException e) {
22             // TODO Auto-generated catch block
23             e.printStackTrace();
24         }
25     }
26     //恢复备忘
27     public void resetMemento(){
28         this.setState(this.originatord.getState());
29     }
30     public Originatord getOriginatord() {
31         return originatord;
32     }
33
34     public void setOriginatord(Originatord originatord) {
35         this.originatord = originatord;
36     }
37
38     public String getState() {
39         return state;
40     }
41
42     public void setState(String state) {
43         this.state = state;
44     }
45
46     /**
47      * 使用克隆进行备忘
48      */
49     @Override
50     protected Originatord clone() throws CloneNotSupportedException {
51         return (Originatord) super.clone();
52
53     }
54
55
56 }

View Code

【3】多状态的备忘模式
《一》多状态发起者

 1 package com.yeepay.sxf.template19;
 2
 3 import java.util.HashMap;
 4
 5 /**
 6  *【 多状态的备忘录模式】
 7  * @author sxf
 8  *
 9  */
10 public class OriginatorDuo {
11     //内部状态
12     private String state1="";
13     private String state2="";
14     private String state3="";
15
16     //创建一个备忘录
17     public MementoDuo createMemenTo(){
18         return new MementoDuo(BeanUtils.backupProp(this));
19     }
20
21     //恢复备忘
22     public void resetMemento(HashMap<String, Object> propMap){
23         BeanUtils.restoreProp(this, propMap);
24     }
25     public String getState1() {
26         return state1;
27     }
28     public void setState1(String state1) {
29         this.state1 = state1;
30     }
31     public String getState2() {
32         return state2;
33     }
34     public void setState2(String state2) {
35         this.state2 = state2;
36     }
37     public String getState3() {
38         return state3;
39     }
40     public void setState3(String state3) {
41         this.state3 = state3;
42     }
43
44 }

View Code

《二》多状态备忘录

 1 package com.yeepay.sxf.template19;
 2
 3 import java.util.HashMap;
 4
 5 /**
 6  * 多状态的备忘录
 7  * @author sxf
 8  *
 9  */
10 public class MementoDuo {
11     //接受HashMap作为状态
12     private HashMap<String, Object> stateMap;
13     //接受一个对象,建立一个备份
14     public MementoDuo(HashMap<String, Object> stateMap){
15         this.stateMap=stateMap;
16     }
17     public HashMap<String, Object> getStateMap() {
18         return stateMap;
19     }
20     public void setStateMap(HashMap<String, Object> stateMap) {
21         this.stateMap = stateMap;
22     }
23
24
25 }

View Code

《三》多状态备忘录的创建和恢复的工具类

 1 package com.yeepay.sxf.template19;
 2
 3 import java.beans.BeanInfo;
 4 import java.beans.Introspector;
 5 import java.beans.PropertyDescriptor;
 6 import java.lang.reflect.Method;
 7 import java.util.HashMap;
 8
 9 /**
10  *  备忘录模式的工具类
11  * @author sxf
12  *
13  */
14 public class BeanUtils {
15     //把bean的所有属性及数值放入到HashMap中
16     public static HashMap<String, Object> backupProp(Object bean){
17         HashMap<String, Object> result=new HashMap<String, Object>();
18         try {
19             //根据反射获取bean的描述
20             BeanInfo beanInfo=Introspector.getBeanInfo(bean.getClass());
21             //获取属性描述
22             PropertyDescriptor[] descriptors=beanInfo.getPropertyDescriptors();
23             //便利所有的属性
24             for(PropertyDescriptor descriptor:descriptors){
25                 //获取当前属性名字
26                 String fieldName=descriptor.getName();
27                 //读取属性的方法
28                 Method getterMethod=descriptor.getReadMethod();
29                 //读取属性的值
30                 Object fieldValue=getterMethod.invoke(bean, new Object[]{});
31                 if(!fieldName.equalsIgnoreCase("class")){
32                     result.put(fieldName, fieldValue);
33                 }
34             }
35         } catch (Exception e) {
36             // TODO: handle exception
37         }
38
39         return result;
40     }
41
42     //把Hashmap的值返回的bean中
43     public static void restoreProp(Object bean,HashMap<String, Object> propMap){
44         try {
45             //获取bean的描述
46             BeanInfo beanInfo=Introspector.getBeanInfo(bean.getClass());
47             //获得属性描述
48             PropertyDescriptor[] descriptors=beanInfo.getPropertyDescriptors();
49             //遍历所有的属性
50             for(PropertyDescriptor des:descriptors){
51                 //属性名字
52                 String fieldName=des.getName();
53                 //如果有这个属性
54                 if(propMap.containsKey(fieldName)){
55                     //写属性的方法
56                     Method setterMethod=des.getWriteMethod();
57                     setterMethod.invoke(bean, new Object[]{
58                         propMap.get(fieldName)
59                     });
60                 }
61             }
62         } catch (Exception e) {
63             // TODO: handle exception
64         }
65     }
66 }

View Code

【4】三个备忘录的公共测试类

 1 package com.yeepay.sxf.template19;
 2 /**
 3  * 备忘录模式测试
 4  * @author sxf
 5  *
 6  */
 7 public class ClientTest {
 8
 9     public static void main(String[] args) {
10         //test01();
11         //test02();
12         test03();
13     }
14
15     /**
16      * 简单的备忘录模式
17      */
18     public static void test01(){
19         //定义发起人
20         Originator originator=new Originator();
21         //初始化状态
22         originator.setState("初始化");
23
24         //定义备忘录管理员
25         Caretaker caretaker=new Caretaker();
26         //给备忘录管理员放入备忘录
27         caretaker.setMemento(originator.createMemento());
28
29         //模拟一系列操作修改发起者的状态
30         originator.setState("失败了");
31
32         //经过一系列操作,回复备忘录
33         originator.restoreMemento(caretaker.getMemento());
34         System.out.println("ClientTest.test01()"+originator.getState());
35     }
36
37     /**
38      * 基于克隆的备忘
39      */
40     public static void test02(){
41         //初始化发起者
42         Originatord originatord=new Originatord();
43         //设置初始化状态
44         originatord.setState("初始化状态");
45
46         //创建备忘
47         originatord.createMemento();
48
49         //经过一列操作,修改状态
50         originatord.setState("失败");
51
52         //恢复备忘
53         originatord.resetMemento();
54         System.out.println("ClientTest.test02()"+originatord.getState());
55     }
56
57     /**
58      * 多状态备忘
59      */
60     public static void test03(){
61         //状态发起者
62         OriginatorDuo rDuo=new OriginatorDuo();
63         //初始化状态
64         rDuo.setState1("初始化1");
65         rDuo.setState2("初始化2");
66         rDuo.setState3("初始化3");
67
68         //创建备忘
69         MementoDuo duo=rDuo.createMemenTo();
70
71         //修改状态
72         rDuo.setState1("失败1");
73         rDuo.setState2("失败2");
74         rDuo.setState3("失败3");
75
76         //恢复备忘
77         rDuo.resetMemento(duo.getStateMap());
78
79         //展示初始化
80         System.out.println("ClientTest.test03()"+rDuo.getState1());
81         System.out.println("ClientTest.test03()"+rDuo.getState2());
82         System.out.println("ClientTest.test03()"+rDuo.getState3());
83     }
84 }

View Code

 

时间: 2024-09-12 18:32:57

设计模式之禅之设计模式-备忘录模式的相关文章

Java设计模式(十九)----备忘录模式

备忘录模式 一. 概念 二. 结构 三. 分类 1."白箱"备忘录模式的实现 2."黑箱"备忘录模式的实现 3."多重"检查点 4."自述历史"模式 引子 我们在编程的时候,经常需要保存对象的中间状态,当需要的时候,可以恢复到这个状 态.比如,我们使用Eclipse进行编程时,假如编写失误(例如不小心误删除了几行代码),我们希望返回删除前的状态,便可以使用Ctrl+Z来进行返 回.下象棋的时候,可以反悔.这时我们便可以使用备忘

设计模式之禅之设计模式-桥梁模式

一:桥梁模式定义        --->桥梁模式(Bridge Pattern)也叫做桥接模式,是一个比较简单的模式        --->将抽象和实现解耦,使得两者可以独立地变化. 二:桥梁模式角色 ● Abstraction--抽象化角色        它的主要职责是定义出该角色的行为,同时保存一个对实现化角色的引用,该角色一般是抽象类.● Implementor--实现化角色        它是接口或者抽象类,定义角色必需的行为和属性.● RefinedAbstraction--修正抽象

设计模式学习笔记(十七)—Memento备忘录模式

一.模式定义: 在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样就可以将该对象恢复到原先保存前的状态. 二.模式解说 在程序运行过程中,某些对象的状态处在转换过程中,可能由于某种原因需要保存此时对象的状态,以便程序运行到某个特定阶段,需要恢复到对象之前处于某个点时的状态.如果使用一些公有接口让其它对象来得到对象的状态,便会暴露对象的实现细节. 三.结构图 1) 备忘录(Memento)角色:备忘录角色存储"备忘发起角色"的内部状态."备忘发起角色

设计模式之禅之设计模式-装饰者模式

一:装饰模式的定义        --->动态地给一个对象添加一些额外的职责.就增加功能来说,装饰模式相比生成子类更为灵活.        --->如果大家还记得代理模式,那么很容易看懂这个类图,装饰类的作用也就是一个特殊的代理类.        --->在装饰模式中,必然有一个最基本.最核心.最原始的接口或抽象类充当Component抽象构件 二:装饰模式的角色        ● Component抽象构件                Component是一个接口或者是抽象类,就是定

设计模式之禅之设计模式-策略模式

一:策略模式的定义        --->是一种比较简单的模式,也叫做政策模式        --->定义一组算法,将每个算法都封装起来,并且使它们之间可以互换 二:策略模式的三个角色 ● Context封装角色        --->它也叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略.算法的直接访问,封装可能存在的变化.● Strategy抽象策略角色        --->策略.算法家族的抽象,通常为接口,定义每个策略或算法必须具有的方法和属性● ConcreteStr

设计模式之禅之设计模式-迭代器模式

一:迭代器模式的定义        --->迭代器模式(Iterator Pattern)目前已经是一个没落的模式,基本上没人会单独写一个迭代器,除非是产品性质的开发        --->它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节.        --->迭代器是为容器服务的,那什么是容器呢? 能容纳对象的所有类型都可以称之为容器,例如Collection集合类型.Set类型等,迭代器模式就是为解决遍历这些容器中的元素而诞生的        --->迭

设计模式之禅之设计模式-模板方法模式

一:模板方法模式的定义        --->定义一个操作中的算法的框架,而将一些步骤延迟到子类中.使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤.        --->模板方法模式确实非常简单,仅仅使用了Java的继承机制,但它是一个应用非常广泛的模式.其中,AbstractClass叫做抽象模板,它的方法分为两类:        ● 基本方法                基本方法也叫做基本操作,是由子类实现的方法,并且在模板方法被调用.        ● 模板方法   

设计模式之禅之设计模式-建造者模式

一:建造者模式的定义        --->建造者模式(Builder Pattern)也叫做生成器模式,其定义如下:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示        ● Product产品类                通常是实现了模板方法模式,也就是有模板方法和基本方法,这个参考模板方法模式.例子中的BenzModel和BMWModel就属于产品类.        ● Builder抽象建造者                规范产品的组建,一般是由子类

设计模式之禅之设计模式-责任链模式

一:责任链模式的定义        --->使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止.        --->责任链模式的重点是在"链"上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果        --->一般会有一个封装类对责任模式进行封装,也就是替代Client类,直接返回链中的第一个处理者,具体链的设置不需要高层次模块关系,这样,更简化了