备忘录模式

备忘录模式概念

第一点:行为设计模式
第二点:用于保存对象的当前状态,并且以后可以恢复到此状态,通俗说法“后悔药”->恢复到想要恢复的地方
第三点:需要保证被保存的对象状态不能被对象从外部访问(目的:为了保护好被保存的这些对象状态的完整性以及内部实现不向外暴露)

备忘录模式定义

在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保护这个状态,这样以后就可以将该对象恢复到原先保存的状态

备忘录模式场景

场景一:需要保存对象在某一时刻的状态或者部分状态
场景二:如果用一个接口(协议)来让其他对象得到这些状态,将暴露对象的实现细节并且破坏对象的封装性,一个对象不希望外界直接访问其内部状态,通过中间对象可以间接访问其封装状态,一个对象不希望外界直接访问其内部状态,通过中间对象可以间接访问其内部状态

备忘录模式角色划分

角色一:(Originator):负责创建一个备忘录,可以记录或者恢复内部状态
角色二:(Memento):备忘录角色,用于存储角色一的内部状态,并且可以防止角色一以外的对象访问角色二
角色三:(Caretaker):负责存储备忘录,不能够向外暴露对备忘录内容进行操作

备忘录模式原理案例

image.png

角色一:(Originator):负责创建一个备忘录,可以记录或者恢复内部状态

//
//  JDQSOriginator.swift
//  Dream_20180720_Memento
//
//  Created by Dream on 2018/7/20.
//  Copyright © 2018年 Tz. All rights reserved.
//

import UIKit

//其次:定义一个创建备忘录角色Originator   
class JDQSOriginator: NSObject {

    var point:Int
    var level:Int
    
    override init() {
        self.point = 100
        self.level = 1
        super.init()
    }
    
    func play() {
        print("游戏开始了,当前进度是第\(self.level),目前的了\(self.point)分...")
        self.level += 1
        self.point += 50
        print("恭喜你升了一级...")
        print("恭喜你积分增加了50分...")
        print("当前等级是第\(self.level)级,目前得到了\(self.point)分...")
    }
    
    func exit() {
        print("-----游戏结束-----")
        print("-----退出游戏,当前等级是\(self.level)-----")
        print("-----游戏结束-----")
    }
    
    //创建
    func createMemo() -> JDQSMemento {
        return JDQSMemento(point: self.point, level: self.level)
    }
    
    //恢复
    func restore(memo:JDQSMemento) {
        print("-----恢复游戏-----")
        self.level = memo.level
        self.point = memo.point
        print("当前等级是第\(self.level)级,目前得到了\(self.point)分...")
    }
    
    func getMemoString() -> String {
        return "第\(self.level)级,积分是\(self.point)分"
    }
    
}

角色二:(Memento):备忘录角色,用于存储角色一的内部状态,并且可以防止角色一以外的对象访问角色二

//
//  JDQSMemento.swift
//  Dream_20180720_Memento
//
//  Created by Dream on 2018/7/20.
//  Copyright © 2018年 Tz. All rights reserved.
//

import UIKit

//首先:定义一个备忘录->JDQS(备忘录角色)
class JDQSMemento: NSObject {

    var point:Int
    var level:Int
    //...
    
    init(point:Int, level:Int) {
        self.point = point
        self.level = level
    }
    
}

角色三:(Caretaker):负责存储备忘录,不能够向外暴露对备忘录内容进行操作

//
//  JDQSCaretaker.swift
//  Dream_20180720_Memento
//
//  Created by Dream on 2018/7/20.
//  Copyright © 2018年 Tz. All rights reserved.
//

import UIKit

//最后:定义一个负责存储备忘录
class JDQSCaretaker: NSObject {
    
    //内存缓存
    private var memo:JDQSMemento?
    
    func write(memo:JDQSMemento) {
        //写入数据库
        self.memo = memo
    }
    
    func read() -> JDQSMemento {
        //数据库读取
        return self.memo!
    }
    
}

备忘录模式-原始状态-命令模式
//
//  BankEntry.swift
//  Dream_20180720_Memento
//
//  Created by Dream on 2018/7/20.
//  Copyright © 2018年 Tz. All rights reserved.
//

import UIKit

//银行实体类
class BankEntry: NSObject {
    //银行数据(时间、用户名...)
    //唯一标示
    let id:Int
    //数量(账户金额)
    let amount:Float
    init(id:Int, amount:Float) {
        self.id = id
        self.amount = amount
    }
}

//
//  Bank.swift
//  Dream_20180720_Memento
//
//  Created by Dream on 2018/7/20.
//  Copyright © 2018年 Tz. All rights reserved.
//

import UIKit

//接收者(演示)
class Bank: NSObject {

    //账户->ID对应(字典)
    private var entrys = [Int:BankEntry]()
    //当前账户ID下标(数量)
    private var nextId = 1
    //总金额(统计总金额)
    private var total:Float = 0
    
    //添加账户(简单逻辑)->命令
    @discardableResult func addEntry(id:Int, amount:Float) -> BankCommand {
        let entry = BankEntry(id: id, amount: amount)
        self.entrys[entry.id] = entry
        total += amount
        nextId += 1
        return createUndoCommand(entry: entry)
    }
    
    private func createUndoCommand(entry:BankEntry) -> BankCommand {
        return BankCommand(block: { (target) in
            let removeObj = target.entrys.removeValue(forKey: entry.id)
            if removeObj != nil {
                //统计金额
                target.total -= (removeObj?.amount)!
            }
        }, receiver: self)
    }
    
    func printEntrys() {
        //排序打印方式
//        entrys.keys.sorted(by: <#T##(Int, Int) throws -> Bool#>)
//        for id in entrys.keys {
//            //打印所有的银行账户
//            print("银行id\(id)")
//        }
        print("金额\(self.total)")
    }
    
}

//
//  BankCommand.swift
//  Dream_20180720_Memento
//
//  Created by Dream on 2018/7/20.
//  Copyright © 2018年 Tz. All rights reserved.
//

import UIKit

//命令->用于保存操作->允许恢复
class BankCommand: NSObject {

    //闭包命令
    private var receiver:Bank
    private var block:(Bank)->Void
    
    init(block:@escaping (Bank)->Void, receiver:Bank) {
        self.block = block
        self.receiver = receiver
    }
    
    func execute() {
        self.block(self.receiver)
    }
    
}

备忘录模式-上面的命令模式改进
//
//  BankEntryMemo.swift
//  Dream_20180720_Memento
//
//  Created by Dream on 2018/7/20.
//  Copyright © 2018年 Tz. All rights reserved.
//

import UIKit

class BankMemo: NSObject {

    //账户->ID对应(字典)
    private var entrys = [BankEntry]()
    //当前账户ID下标(数量)
    private var nextId = 1
    //总金额(统计总金额)
    private var total:Float = 0
    
    
    init(org:BankOriginator) {
        for item in org.entrys.values {
            self.entrys.append(item)
        }
        self.nextId = org.nextId
        self.total = org.total
    }
    
    func apply(org:BankOriginator) {
        org.total = self.total
        org.nextId = self.nextId
        for item in self.entrys {
            org.entrys[item.id] = item
        }
    }
    
}

//
//  BankOriginator.swift
//  Dream_20180720_Memento
//
//  Created by Dream on 2018/7/20.
//  Copyright © 2018年 Tz. All rights reserved.
//

import UIKit

class BankOriginator: NSObject {

    
    //账户->ID对应(字典)
    var entrys = [Int:BankEntry]()
    //当前账户ID下标(数量)
    var nextId = 1
    //总金额(统计总金额)
    var total:Float = 0
    
    //添加账户(简单逻辑)->命令
    func addEntry(id:Int, amount:Float) {
        let entry = BankEntry(id: id, amount: amount)
        self.entrys[entry.id] = entry
        total += amount
        nextId += 1
    }
    
    func createMemo() -> BankMemo {
        return BankMemo(org: self)
    }
    
    //如果定了抽象备忘录需要判定
    func applyMemo(memo:BankMemo) {
        memo.apply(org: self)
    }
    
    //添加一个restore即可
    
    func printEntry() {
        print("总额度:\(self.total)")
    }
    
}

备忘录模式变种
//
//  JsonMemo.swift
//  Dream_20180720_Memento
//
//  Created by Dream on 2018/7/20.
//  Copyright © 2018年 Tz. All rights reserved.
//

import UIKit

//备忘录模式变种->数据类型改变
class JsonMemo : NSObject{

    private var jsonStr:String?
    
    //方法重载
    init(jsonStr:String) {
        //属性赋值
        
        super.init()
    }
    
    init(org:JsonOriginator) {
        //属性赋值在前面(语法问题,自己看)
        self.jsonStr = ""
        super.init()
        //创建对象之后才能够调用(self对象方法)
        self.jsonStr = self.toString(org: org)
    }
    
    func toString(org:JsonOriginator) -> String {
        //将对象->json字符串
        //可以用框架
        var dic = [String:Any]()
        dic["total"] = org.total
        dic["nextId"] = org.nextId
        //存放字典
        var entryArray = [[String:Any]]()
        for entry in org.entrys.values {
            var entryChild = [String:Any]()
            entryChild["id"] = entry.id
            entryChild["amount"] = entry.amount
            entryArray.append(entryChild)
        }
        dic["entrys"] = entryArray
        if let data = try? JSONSerialization.data(withJSONObject: dic, options: []){
            return String(data: data, encoding: String.Encoding.utf8)!
        }
        return ""
    }
    
    //将json字符串->转为->对象
    //恢复
    func apply(org:JsonOriginator) {
        if let data = jsonStr?.data(using: String.Encoding.utf8, allowLossyConversion: false){
            if let dic = try? JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] {
                org.total = (dic?["total"] as? Float)!
                org.nextId = (dic?["nextId"] as? Int)!
                if let entryDic = dic?["entrys"] as? [[String:Any]] {
                    org.entrys.removeAll()
                    for entry in entryDic {
                        let id = entry["id"] as! Int
                        let amount = entry["amount"] as! Float
                        org.entrys[id] = BankEntry(id: id, amount: amount)
                    }
                }
            }
        }
    }
    
}

//
//  JsonOriginator.swift
//  Dream_20180720_Memento
//
//  Created by Dream on 2018/7/20.
//  Copyright © 2018年 Tz. All rights reserved.
//

import UIKit

class JsonOriginator: NSObject {

    //账户->ID对应(字典)
    var entrys = [Int:BankEntry]()
    //当前账户ID下标(数量)
    var nextId = 1
    //总金额(统计总金额)
    var total:Float = 0
    
    
    //添加账户(简单逻辑)->命令
    func addEntry(id:Int, amount:Float) {
        let entry = BankEntry(id: id, amount: amount)
        self.entrys[entry.id] = entry
        total += amount
        nextId += 1
    }
    
    func createMemo() -> JsonMemo {
        return JsonMemo(org:self)
    }
    
    //如果定了抽象备忘录需要判定
    func applyMemo(memo:JsonMemo) {
        //恢复
        memo.apply(org: self)
    }
    
    //添加一个restore即可
    
    func printEntry() {
        print("总额度:\(self.total)")
    }
    
}

备忘录模式UML

至少是依赖关系

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容

  • 1 场景问题# 1.1 开发仿真系统## 考虑这样一个仿真应用,功能是:模拟运行针对某个具体问题的多个解决方案,记...
    七寸知架构阅读 2,140评论 1 50
  • 定义 备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式。 备忘录对象...
    步积阅读 2,933评论 0 2
  • 1.初识备忘录模式 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对...
    王侦阅读 469评论 0 0
  • 在阎宏博士的《JAVA与模式》一书中开头是这样描述备忘录(Memento)模式的:备忘录模式又叫做快照模式(Sna...
    Ant_way阅读 784评论 0 0
  • 一种别离了无音, 二地牵念徒留痕。 三山顶上松峰立, 四海浪前波谷深。 五湖归来知路远, 六根断去恐情真。 七香宝...
    月月如歌阅读 308评论 9 5