备忘录模式

作者: 架构师的一小步 | 来源:发表于2019-03-19 08:45 被阅读0次

    备忘录模式概念

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

    备忘录模式定义

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

    备忘录模式场景

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

    备忘录模式角色划分

    角色一:(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

    至少是依赖关系

    相关文章

      网友评论

        本文标题:备忘录模式

        本文链接:https://www.haomeiwen.com/subject/pdeipqtx.html