设计模式-备忘录模式

1. 备忘录模式概述

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

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

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

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

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

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

备忘录模式, Swift版本客户端代码:编程语言

备忘录模式代码:.net

// 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. 备忘录模式的封装

备忘录是一个很特殊的对象,只有原发器对它拥有控制的权力,负责人只负责管理,而其余类没法访问到备忘录,所以咱们须要对备忘录进行封装。设计

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

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

4. 备忘录模式总结

备忘录模式在不少软件的使用过程当中广泛存在,可是在应用软件开发中,它的使用频率并不过高,由于如今不少基于窗体和浏览器的应用软件并无提供撤销操做。若是须要为软件提供撤销功能,备忘录模式无疑是一种很好的解决方案。在一些字处理软件、图像编辑软件、数据库管理系统等软件中备忘录模式都获得了很好的应用。对象

4.1 主要优势

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

4.2 主要缺点

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

4.3 适用场景

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

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

相关文章
相关标签/搜索