文档章节

设计模式-备忘录模式

hell03W
 hell03W
发布于 2016/11/25 16:02
字数 1693
阅读 59
收藏 0

钉钉、微博极速扩容黑科技,点击观看阿里云弹性计算年度发布会!>>>

1. 备忘录模式概述

备忘录模式提供一种状态恢复的实现机制, 用户可以方便的回到一个特定的历史步骤, 当新的状态无效或者存在问题时候, 可以使用暂时存起来的备忘录将状态复原, 当前很多软件中提供的撤销操作, 其中使用了备忘录模式.

备忘录模式: 在不破坏封装的前提下, 捕获一个对象的内部状态, 并在该对象之外保存这个状态, 这样可以在以后将状态恢复到原先保存的状态. 它是一种对象行为模式.

备忘录模式的核心是备忘录类以及用于管理备忘录的负责人类的设计, 其结构如下所示:

  • 原发器(Originator): 它是一个普通类, 可以创建一个备忘录, 并存储它的当前内部状态, 也可以使用备忘录来恢复其内部状态, 一般将需要保存内部状态的类设计为原发器.
  • 备忘录(Memento): 存储原发器的内部状态, 根据原发器来决定保存那些内部状态. 备忘录的设计一般可以参考原发器的设计, 根据实际需要确定备忘录中的属性. 需要注意的是除了原发器本身和负责人之外, 备忘录对象不能直接提供其它类使用, 原发器的设计在不同的编程语言中实现机制会有所不同.
  • 负责人(Caretaker): 负责人又称为管理者, 它负责保存备忘录, 但是不能对备忘录的内容进行检查和操作. 在负责人类中有一个或者多个备忘录对象, 它只负责存储对象, 而不能修改对象, 也无需知道对象的实现细节.

备忘录模式关键在于如何设计备忘录类和负责人类. 由于在备忘录中存储的是原发器的中间状态, 因此需要防止原发器以外的其它对象访问备忘录, 特别是不允许其它对象来修改备忘录.

2. 中国象棋例子的Swift实现

备忘录模式, Swift版本客户端代码:

备忘录模式代码:

// ChessMan
class ChessMan: NSObject {
    
    var label: String?
    var x: Int?
    var y: Int?
    
    // 初始化棋子状态
    init(label: String, x: Int, y: Int) {
        
        self.label = label
        self.x = x
        self.y = y
    }
    
    // 移动棋子
    func move(x: Int, y: Int) {
        
        self.x = x
        self.y = y
    }
    
    
    // 保存状态, 返回当前对象状态的类, 即备忘录
    func save() -> ChessmanMemento {
        return ChessmanMemento(chessman: self)
    }
    
    // 恢复到一个历史状态, 参数是一个状态
    func restore(memento: ChessmanMemento) {
        
        label = memento.label
        x = memento.x
        y = memento.y
    }
}





// ChessmanMemento
class ChessmanMemento: NSObject {
    
    var label: String
    var x: Int
    var y: Int
    
    init(chessman: ChessMan) {
        
        label = chessman.label ?? ""
        x = chessman.x ?? 0
        y = chessman.y ?? 0
    }

}





// MementoCaretaker
class MementoCaretaker: NSObject {
    
    lazy var mementoArray = [ChessmanMemento]()
    
    
    // 根据历史状态, 从状态列表中获取一个历史状态
    func getMemento(index: Int) -> ChessmanMemento {
        return mementoArray.remove(at: index)
    }
    
    // 获取最近的状态
    func getLatestMemento() -> ChessmanMemento {
        
        return mementoArray.removeLast()
    }
    
    // 获取最老的的状态
    func getOldestMemento() -> ChessmanMemento {
        
        return mementoArray.removeFirst()
    }
    
    // 添加一个状态
    func addMemento(memento: ChessmanMemento) {
        mementoArray.append(memento)
    }

}

3. 备忘录模式的封装

备忘录是一个很特殊的对象,只有原发器对它拥有控制的权力,负责人只负责管理,而其他类无法访问到备忘录,因此我们需要对备忘录进行封装。

为了实现对备忘录对象的封装,需要对备忘录的调用进行控制,对于原发器而言,它可以调用备忘录的所有信息,允许原发器访问返回到先前状态所需的所有数据;对于负责人而言,只负责备忘录的保存并将备忘录传递给其他对象;对于其他对象而言,只需要从负责人处取出备忘录对象并将原发器对象的状态恢复,而无须关心备忘录的保存细节。理想的情况是只允许生成该备忘录的那个原发器访问备忘录的内部状态。

在实际开发中,原发器与备忘录之间的关系是非常特殊的,它们要分享信息而不让其他类知道,实现的方法因编程语言的不同而有所差异,在C++中可以使用friend关键字,让原发器类和备忘录类成为友元类,互相之间可以访问对象的一些私有的属性;在Java语言中可以将原发器类和备忘录类放在一个包中,让它们之间满足默认的包内可见性,也可以将备忘录类作为原发器类的内部类,使得只有原发器才可以访问备忘录中的数据,其他对象都无法使用备忘录中的数据。

4. 备忘录模式总结

备忘录模式在很多软件的使用过程中普遍存在,但是在应用软件开发中,它的使用频率并不太高,因为现在很多基于窗体和浏览器的应用软件并没有提供撤销操作。如果需要为软件提供撤销功能,备忘录模式无疑是一种很好的解决方案。在一些字处理软件、图像编辑软件、数据库管理系统等软件中备忘录模式都得到了很好的应用。

4.1 主要优点

  1. 它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原。
  2. 备忘录实现了对信息的封装,一个备忘录对象是一种原发器对象状态的表示,不会被其他代码所改动。备忘录保存了原发器的状态,采用列表、堆栈等集合来存储备忘录对象可以实现多次撤销操作。

4.2 主要缺点

资源消耗过大,如果需要保存的原发器类的成员变量太多,就不可避免需要占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源。

4.3 适用场景

  1. 保存一个对象在某一个时刻的全部状态或部分状态,这样以后需要时它能够恢复到先前的状态,实现撤销操作。
  2. 防止外界对象破坏一个对象历史状态的封装性,避免将对象历史状态的实现细节暴露给外界对象。

Reference: http://blog.csdn.net/lovelion/article/details/7526747

hell03W
粉丝 10
博文 145
码字总数 109892
作品 0
朝阳
程序员
私信 提问
加载中
请先登录后再评论。
单例模式(Singleton Pattern)

创建型模式: 设计模式-单例模式 设计模式-建造者模式 设计模式-工厂方法模式 设计模式-简单工厂模式 设计模式-抽象工厂模式 设计模式-原型模式 行为型模式: 设计模式-策略模式 设计模式-状...

南柯好萌
01/31
19
0
设计模式--刘伟(转)

原文:https://blog.csdn.net/lovelion/article/details/17517213 2012年-2013年,Sunny在CSDN技术博客中陆续发表了100多篇与设计模式学习相关的文章,涵盖了七个面向对象设计原则和24个设计...

osc_k5ta3dng
2018/05/16
5
0
23种设计模式UML图

创建型设计模式 单例模式模式 工厂模式模式 抽象工厂模式 建造者模式 原型模式 结构型设计模式 适配器模式 装饰模式 桥接模式 享元模式 代理模式 组合模式 行为型设计模式 模板方法模式 观察...

osc_w5x85e9u
2019/01/03
2
0
101JAVA设计模式--业务逻辑实现扩展,框架使用分析总结

23中设计模式目录如下: 工厂模式 抽象工厂模式 单例模式 建造者模式 原型模式 适配器模式 桥接模式 过滤器模式 组合模式 装饰器模式 外观模式 享元模式 代理模式 责任链模式 命令模式 解释器...

osc_h9x23mw1
2019/12/07
8
0
Java开发中的23种设计模式详解

总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接...

osc_ld3u7lka
2018/07/27
9
0

没有更多内容

加载失败,请刷新页面

加载更多

SpringCloud 应用在 Kubernetes 上的最佳实践 — 开发篇

作者 | 孤弋 阿里云高级技术专家,负责 EDAS 的开发和用户体验优化工作。 前言 近年来,云原生、Kubernetes、微服务、SpringCloud 这些名词在技术圈内不绝于耳,数据显示,使用 SpringCloud ...

阿里云技术博客
25分钟前
0
0
如何能够高效率学习Web前端技术

  Web前端开发作为前端技术的重要组成,一直占据着重要的地位,整个IT行业内有大量的前端开发从业者,随着移动互联网、大数据和人工智能的发展,目前前端的知识体系也在逐渐丰富。   要想...

SXXpenguin
25分钟前
0
0
Spring Boot 2.3.0正式发布:优雅停机、配置文件位置通配符新特性一览

当大潮退去,才知道谁在裸泳。。关注公众号【BAT的乌托邦】开启专栏式学习,拒绝浅尝辄止。本文 https://www.yourbatman.cn 已收录,里面一并有Spring技术栈、MyBatis、中间件等小而美的专栏...

osc_odp8kgup
26分钟前
0
0
HttpMessageConverter是这样转换数据的

Java Web 人员经常要设计 RESTful API(如何设计好的RESTful API),通过 json 数据进行交互。那么前端传入的 json 数据如何被解析成 Java 对象作为 API入参,API 返回结果又如何将 Java 对象...

tan日拱一兵
2019/05/27
7
0
angular浏览器兼容性问题解决方案

问题:edge浏览器下,固定列的边框消失 原因:ng-zorro-antd表格组件使用nzLeft和nzRight指令固定的表格列,这两个指令的实现css3中的标签: position: -webkit-sticky !important;positio...

osc_elbmybcg
27分钟前
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部