文档章节

设计模式-备忘录模式

hell03W
 hell03W
发布于 2016/11/25 16:02
字数 1693
阅读 18
收藏 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

本文转载自:http://blog.csdn.net/lovelion/article/details/7526747

共有 人打赏支持
hell03W
粉丝 9
博文 145
码字总数 109892
作品 0
朝阳
程序员
私信 提问
(目录)设计模式(可复用面向对象软件的基础)

本系列“设计模式”博客使用Golang语言实现算法。所谓算法是指解决一个问题的步骤,个人觉得不在于语言。小弟只是最近学习Golang,所以顺带熟练一下语法知识,别无它意。 本系列博客主要介绍...

chapin
2015/01/13
0
0
你需要了解的23种JavaScript设计模式

为什么要学习设计模式? 在许多访谈中,你可能会遇到很多面向对象编程中的接口,抽象类,代理和以及其他与设计模式相关的问题。 一旦了解了设计模式,它会让你轻松应对任何访谈,并可以在你的...

java高级架构牛人
06/02
0
0
java设计模式-- 单例模式

在很久之前,也就是在大二暑假的时候,那时候看马士兵的视频教程中有提到很多的设计模式。 java的设计模式大致可以分为3大类,23种设计模式。 其中,创建型模式有5种:单例模式、建造者模式、...

爱学习的逃课君
2014/11/27
0
0
设计模式 2014-12-19

book: 阎宏《JAVA与模式》 架构设计栏目 http://blog.csdn.net/enterprise/column.html 概要: http://bbs.csdn.net/forums/Embeddeddriver 23种设计模式分别是: 1.单例模式 2.工厂方法模式...

jayronwang
2014/12/19
0
0
迈向大牛的重要一步——掌握设计模式

IT职场的小菜经常有这样的疑问: 为什么一个相似的功能,大牛一会儿就搞定,然后悠闲地品着下午茶逛淘宝;而自己加班加点搞到天亮还做不完。 为什么用户提出需求变更后,大牛只需潇洒地敲敲键...

一枚Sir
2015/04/10
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周三乱弹 —— 你是靠自己努力才失败的

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 小小编辑:推荐歌曲 《Raveena》- Raveena 《Raveena》- Raveena 手机党少年们想听歌,请使劲儿戳(这里) 11月18日,俞敏洪在某论坛演讲中称...

小小编辑
56分钟前
313
7
firewalld

1. firewalld 是什么 CentOS中默认是有 firewalld, iptables, etablesd firewalld 是 CentOS7/RadHat7 中默认的防火墙管理工具. firewalld 工具用来管理里netfilter, 不过底层还是调用的还是...

Fc丶
今天
4
0
Java 源代码和 C 源代码的运行区别

与其他程序的执行方式和编译方式不同。 Java 源代码需要进行编译成字节码后在 Java 虚拟机上运行,这样 Java 程序能够保持独立性和跨平台功特性。 请参考下图。 https://www.cwiki.us/pages...

honeymose
今天
6
0
Apache限定目录解析PHP,限制user_agent,PHP相关的配置

Apache限定目录解析PHP 配置前访问upload/index.php [root@test-a ~]# curl -x192.168.77.139:80 'www.test.com/upload/index.php'This is upload diretory 配置,/usr/local/apache2.4/......

野雪球
今天
6
0
java.util.Concurrent.Exchanger源码

类图 源码: package java.util.concurrent;import java.util.concurrent.atomic.AtomicInteger;import java.util.concurrent.atomic.AtomicReference;import java.util.concurrent......

狼王黄师傅
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部