文档章节

设计模式-备忘录模式

hell03W
 hell03W
发布于 2016/11/25 16:02
字数 1693
阅读 20
收藏 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
朝阳
程序员
私信 提问
设计模式 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
设计模式Java Design Pattern-工厂方法模式FactoryMethod

我的博客 一、 设计模式的分类 大体可以分为三类: 创建型模式(5个) 单例模式、原型模式、工厂方法模式、抽象工厂模式、建造者模式 结构性模式(7个) 适配器模式、装饰器模式、代理模式、...

勇敢写信
2018/03/22
0
0
【设计模式笔记】(十六)- 代理模式

一、简述 代理模式(Proxy Pattern),为其他对象提供一个代理,并由代理对象控制原有对象的引用;也称为委托模式。 其实代理模式无论是在日常开发还是设计模式中,基本随处可见,中介者模式中...

MrTrying
2018/06/24
0
0
设计模式(Swift) - 3.观察者模式、建造者模式

上一篇 设计模式(Swift) - 2.单例模式、备忘录模式和策略模式中讲了三种常见的设计模式. 单例模式: 限制了类的实例化,一个类只能实例化一个对象,所有对单例对象的引用都是指向了同一个对象....

Dariel
2018/07/01
0
0
(目录)设计模式(可复用面向对象软件的基础)

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

chapin
2015/01/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Linux 权限

权限 0 000 --- 无权限 1 001 --x 执行权限 2 010 -w- 写权限 3 011 -wx 写和执行 4 100 r-- 读权限 5 101 r-x 读和执行 6 110 rw- 读和写 7 111 rwx 读写执行 755 : rwxr-xr-x 660 : rw-r...

忙碌的小蜜蜂
25分钟前
0
0
21分钟教会你分析MaxCompute账单

21分钟教会你分析MaxCompute账单 背景 阿里云大计算服务MaxCompute是一款商业化的大数据分析平台,其计算资源有预付费和后付费两种计费方式。并且产品每天按照project为维度进行计量计费(账...

阿里云云栖社区
28分钟前
0
0
Docker使用 linuxserver/letsencrypt 生成SSL证书最全解析及实践

本文使用 HTTP 和 DNS 两种校验方式对 Docker 下 linuxserver/letsencrypt 项目进行了实践。生成SpringBoot可用证书,使用 Nginx 的 htpasswd 来对网站进行密码保护,并测试使用 fail2ban 防...

java菜分享
29分钟前
0
0
代码吃鸡:Python-Robocode

最近看到一个很有“未来感”的新闻: 一辆特斯拉在拉斯维加斯出了车祸,撞“死”了一个……emmmm……机器人。不知道是意外还是炒作,又或者是这位机器人故意碰瓷,反正人们也无法从受害者口中...

crossin
33分钟前
0
0
什么是公网IP、内网IP和NAT转换?

搞网络通信应用开发的程序员,可能会经常听到外网IP(即互联网IP地址)和内网IP(即局域网IP地址),但他们的区别是什么? 1、引言 搞网络通信应用开发的程序员,可能会经常听到外网IP(即互联网I...

Linux就该这么学
43分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部