zoukankan      html  css  js  c++  java
  • 设计模式之备忘录模式(Memento)详解及代码示例

    一、备忘录模式的定义与特点

      备忘录(Memento)模式的定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。

      备忘录模式能记录一个对象的内部状态,当用户后悔时能撤销当前操作,使数据恢复到它原先的状态。

    二、备忘录模式优缺点

      备忘录模式是一种对象行为型模式,其主要优点如下:

    • 提供了一种可以恢复状态的机制。当用户需要时能够比较方便地将数据恢复到某个历史的状态。
    • 实现了内部状态的封装。除了创建它的发起人之外,其他对象都不能够访问这些状态信息。
    • 简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。

      其主要缺点是:

    • 资源消耗大。如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。

    三、备忘录模式的实现

      备忘录模式的核心是设计备忘录类以及用于管理备忘录的管理者类,备忘录模式的主要角色如下:

    • 发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
    • 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
    • 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。

      备忘录模式的结构图如图所示:

                

      实现代码如下:

    public class MementoPattern
    {
        public static void main(String[] args)
        {
            Originator or=new Originator();
            Caretaker cr=new Caretaker();       
            or.setState("S0"); 
            System.out.println("初始状态:"+or.getState());           
            cr.setMemento(or.createMemento()); //保存状态      
            or.setState("S1"); 
            System.out.println("新的状态:"+or.getState());        
            or.restoreMemento(cr.getMemento()); //恢复状态
            System.out.println("恢复状态:"+or.getState());
        }
    }
    //备忘录
    class Memento
    { 
        private String state; 
        public Memento(String state)
        { 
            this.state=state; 
        }     
        public void setState(String state)
        { 
            this.state=state; 
        }
        public String getState()
        { 
            return state; 
        }
    }
    //发起人
    class Originator
    { 
        private String state;     
        public void setState(String state)
        { 
            this.state=state; 
        }
        public String getState()
        { 
            return state; 
        }
        public Memento createMemento()
        { 
            return new Memento(state); 
        } 
        public void restoreMemento(Memento m)
        { 
            this.setState(m.getState()); 
        } 
    }
    //管理者
    class Caretaker
    { 
        private Memento memento;       
        public void setMemento(Memento m)
        { 
            memento=m; 
        }
        public Memento getMemento()
        { 
            return memento; 
        }
    }

      测试结果如下:

    初始状态:S0
    新的状态:S1
    恢复状态:S0

    四、备忘录模式的应用场景

      前面学习了备忘录模式的定义与特点、结构与实现,现在来看该模式的以下应用场景。

    • 需要保存与恢复数据的场景,如玩游戏时的中间结果的存档功能。
    • 需要提供一个可回滚操作的场景,如 Word、记事本、Photoshop,Eclipse 等软件在编辑时按 Ctrl+Z 组合键,还有数据库中事务操作。

    五、备忘录模式的扩展

      在前面介绍的备忘录模式中,有单状态备份的例子,也有多状态备份的例子。下面介绍备忘录模式如何同原型模式混合使用。在备忘录模式中,通过定义“备忘录”来备份“发起人”的信息,而原型模式的 clone() 方法具有自备份功能,所以,如果让发起人实现 Cloneable 接口就有备份自己的功能,这时可以删除备忘录类,其结构图如图所示:

              

       代码如下所示:

    public class PrototypeMemento
    {
        public static void main(String[] args)
        {
            OriginatorPrototype or=new OriginatorPrototype();
            PrototypeCaretaker cr=new PrototypeCaretaker();       
            or.setState("S0"); 
            System.out.println("初始状态:"+or.getState());           
            cr.setMemento(or.createMemento()); //保存状态      
            or.setState("S1"); 
            System.out.println("新的状态:"+or.getState());        
            or.restoreMemento(cr.getMemento()); //恢复状态
            System.out.println("恢复状态:"+or.getState());
        }
    }
    //发起人原型
    class OriginatorPrototype  implements Cloneable
    { 
        private String state;     
        public void setState(String state)
        { 
            this.state=state; 
        }
        public String getState()
        { 
            return state; 
        }
        public OriginatorPrototype createMemento()
        { 
            return this.clone(); 
        } 
        public void restoreMemento(OriginatorPrototype opt)
        { 
            this.setState(opt.getState()); 
        }
        public OriginatorPrototype clone()
        {
            try
            {
                return (OriginatorPrototype) super.clone();
            }
            catch(CloneNotSupportedException e)
            {
                e.printStackTrace();
            }
            return null;
        }
    }
    //原型管理者
    class PrototypeCaretaker
    { 
        private OriginatorPrototype opt;       
        public void setMemento(OriginatorPrototype opt)
        { 
            this.opt=opt; 
        }
        public OriginatorPrototype getMemento()
        { 
            return opt; 
        }
    }

      运行结果如下:

    初始状态:S0
    新的状态:S1
    恢复状态:S0
  • 相关阅读:
    【Azure 应用服务】在Azure App Service多实例的情况下,如何在应用中通过代码获取到实例名(Instance ID)呢?
    【Azure 应用服务】App Service For Windows 中如何设置代理实现前端静态文件和后端Java Spring Boot Jar包
    【Azure Developer】使用Azure Key Vault 的Key签名后,离线验证的一些参考资料
    【Azure Function】调试 VS Code Javascript Function本地不能运行,报错 Value cannot be null. (Parameter 'provider')问题
    【Azure 应用服务】App Service 使用Tomcat运行Java应用,如何设置前端网页缓存的相应参数呢(Xms512m Xmx1204m)?
    【Azure API 管理】APIM添加Logtoeventhub的策略后,一些相关APIM与Event Hub的问题
    【Azure API 管理】为调用APIM的请求启用Trace 调试APIM Policy的利器
    【Azure 事件中心】China Azure上是否有Kafka服务简答
    【Azure 应用服务】探索在Azure上设置禁止任何人访问App Service的默认域名(Default URL)
    【Azure 微服务】记一次错误的更新Service Fabric 证书而引发的集群崩溃而只能重建
  • 原文地址:https://www.cnblogs.com/jing99/p/12617294.html
Copyright © 2011-2022 走看看