設計模式(Swift) - 2.單例模式、備忘錄模式和策略模式

上一篇 設計模式(Swift) - 1.MVC和代理 中涉及到了三點,類圖,MVC和代理模式.git

  • 類圖用來清晰直觀的表達設計模式.
  • 做爲Cocoa框架的核心結構模式,MVC怎樣處理視圖、模型、控制器之間的關係.
  • 將我想作的事委託給有能力的人的代理模式.

1. 單例模式(Singleton Pattern)

1.單例概述

單例限制了類的實例化,一個類只能實例化一個對象,全部對單例對象的引用都是指向了同一個對象. github

2.單例的使用

// 定義一個單例
final public class MySingleton {
    static let shared = MySingleton()
    private init() {}  // 私有化構造方法(若是有須要也能夠去掉)
}

// 使用
let s1 = MySingleton.shared
let s2 = MySingleton.shared
// let s3 = MySingleton() // 報錯
dc.address(o: s1)   // 0x000060400000e5e0
dc.address(o: s2)   // 0x000060400000e5e0
複製代碼

相比OC,swift中單例的實現簡化了很多,swift中可使用let這種方式來保證線程安全.編程

3.單例使用的優缺點

  • 優勢:
    1.因爲單例能保證一個對象存在,咱們能夠對某些操做進行統一管理,好比,app開發中用戶信息的保存和讀取,如後臺開發中服務器配置信息的管理操做.這樣能夠有效的避免沒必要要的對象的建立和銷燬,提升開發效率.
  • 缺點:
    1. 單例模式本質上延長了對象的聲明週期,若是強引用了比較大的對象,不可避免的會形成內存問題,因此在適當的時候須要進行重置單例的操做.
    2. 因爲單例是全局共享,也就意味着整個項目中均可以對單例進行操做,使得出現問題比較難定位.

2. 備忘錄模式(Memento Pattern)

1.備忘錄模式概述

經過備忘錄模式咱們能夠把某個對象保存在本地,並在適當的時候恢復出來. swift

備忘錄模式整體來講分爲三部分:

  • 發起人(Originator): 負責建立一個備忘錄對象,用以保存當前的狀態,並可以使用備忘錄恢復內部狀態。
  • Memento(備忘錄): 負責存儲Originator對象,在swift中由Codable實現.
  • Caretaker(管理者): 負責備忘錄的保存與恢復工做.

Swift tips: Codable Codable是swift4推出來的新特性,全部基本類型都實現了 Codable 協議,只要自定義的對象遵照了該協議,就能夠保存和恢復所須要的對象. 本質上Codable,就是Decodable和Encodable的集合. 具體拓展能夠看這裏Swift 4 踩坑之 Codable 協議設計模式

public typealias Codable = Decodable & Encodable
複製代碼

2.備忘錄模式舉例

我的用戶信息的本地化存儲,包括用戶token啊之類的.安全

1.我的信息操做的業務邏輯:
// MARK: - Originator(發起人)
public class UserInfo: Codable {
    
    static let shared = UserInfo()
    private init() {}
    
    public var isLogin: Bool = false
    
    public var account: String?
    public var age: Int?
    
    var description: String {
        return "account:\(account ?? "爲空"), age:\(age ?? 0)"
    }

}

// MARK: - 備忘錄(Memento): 負責存儲Originator對象,swift中由Codable實現


// MARK: - 管理者(CareTaker)
public class UserInfoTaker {
    
    public static let UserInforKey = "UserInfoKey"
    
    private static let decoder = JSONDecoder()
    private static let encoder = JSONEncoder()
    private static let userDefaults = UserDefaults.standard
    
    public static func save(_ p: UserInfo) throws {
        
        let data = try encoder.encode(p)
        userDefaults.set(data, forKey: UserInforKey)
    }
    
    public static func load() throws -> UserInfo {
        
        guard let data = userDefaults.data(forKey: UserInforKey),
            let userInfo = try? decoder.decode(UserInfo.self, from: data)
            else {
                throw Error.UserInfoNotFound
        }
        
        // decode生成的對象不是單例對象,須要轉換成單例對象
        // 若是你有更好的實現方式歡迎交流
        let userInfoS = UserInfo.shared
        userInfoS.account = userInfo.account
        userInfoS.age = userInfo.age
        userInfoS.isLogin = userInfo.isLogin
        
        return userInfoS
    }
    
    public enum Error: String, Swift.Error {
        case UserInfoNotFound
    }
}
複製代碼
2.我的信息操做:
let userInfo = UserInfo.shared
    userInfo.isLogin = true
    userInfo.account = "132154"
    userInfo.age = 16

    // 保存
    do {
        try UserInfoTaker.save(userInfo)
    }catch {
        print(error)
    }

    // 讀取
    do {
        let newUserInfo = try UserInfoTaker.load()
        
        dc.log(newUserInfo.description) // account:132154, age:16
        dc.address(o: newUserInfo) // 0x000060000009a400
        
    }catch {
        print(error)
    }

    dc.log(userInfo.description) // account:132154, age:16
    dc.address(o: userInfo) // 0x000060000009a400
複製代碼

備忘錄的最大好處就是能夠恢復到特定的狀態,但每次的讀寫操做須要消耗必定的系統資源,因此在某些場景下能夠將單例模式和備忘錄模式結合來統一管理操做數據.服務器

3. 策略模式(Strategy Pattern)

1.策略模式概述

在平常開發中,咱們常常會碰到邏輯分支,咱們通常會用 if else或者switch去處理,但其實還有更好的方式: 策略模式. 策略模式抽象並封裝業務細節,只給出相關的策略接口做爲切換. app

策略模式整體來講分爲三部分:

  • 策略模式的使用者: 爲了統一直觀的使用策略模式,咱們一般會用一個switch語句再作一層封裝.
  • 策略協議: 抽象出策略對象須要實現的屬性,方法.
  • 策略對象: 具體的業務邏輯實現者.

2.策略模式舉例

實現一個商場打折的例子,分爲三種狀況,原價購買,按照一個折扣購買,滿多少返現多少(滿100減20).框架

能夠先思考下再看代碼.ui

1.實現商場打折的業務邏輯:
// 策略協議
protocol DiscountStrategy {
    // 支付價格
    func payment(money: Double) -> Double
}


// 原價購買
class DiscountNormal: DiscountStrategy {
    func payment(money: Double) -> Double {
        return money
    }
}

// 打折
class DiscountRebate: DiscountStrategy {
    private let rebate: Double // 折扣
    
    init(rebate: Double) {
        self.rebate = rebate
    }
    func payment(money: Double) -> Double {
        return money * rebate/10.0
    }
}

// 返現
class DiscountReturn: DiscountStrategy {
    private let moneyCondition: Double // 滿
    private let moneyReturn: Double // 返

    init(moneyCondition: Double, moneyReturn: Double) {
        self.moneyCondition = moneyCondition
        self.moneyReturn = moneyReturn
    }
    
    func payment(money: Double) -> Double {
        return money - (Double(Int(money/moneyCondition)) * moneyReturn)
    }
}

// 策略枚舉
enum PayMentStyle {
    case normal
    case rebate(rebate: Double)
    case `return`(moneyCondition: Double, moneyReturn: Double)
}

// 策略管理
class DiscountContext {
    var discountStrategy: DiscountStrategy?
    
    init(style: PayMentStyle) {
        switch style { // 對應的三種方式
        case .normal:
            discountStrategy = DiscountNormal()
            
        case .rebate(rebate: let money):
            discountStrategy = DiscountRebate(rebate: money)
            
        case .return(moneyCondition: let condition, moneyReturn: let `return`):
            discountStrategy = DiscountReturn(moneyCondition: condition, moneyReturn: `return`)
            
        }
    }
    
    func getResult(money: Double) -> Double {
       return discountStrategy?.payment(money: money) ?? 0
    }
}
複製代碼
2.使用:
let money: Double = 800
        
 let normalPrice = DiscountContext(style: .normal).getResult(money: money)
 let rebatePrice = DiscountContext(style: .rebate(rebate: 8)).getResult(money: money)
 let returnPrice = DiscountContext(style: .return(moneyCondition: 100, moneyReturn: 20)).getResult(money: money)
        
 print("正常價格:\(normalPrice)") // 正常價格:800.0
 print("打八折:\(rebatePrice)") // 打八折:640.0
 print("滿100返20:\(returnPrice)") // 滿100返20:640.0

複製代碼

以上就是一個簡單的策略模式實現,經過DiscountContext來管理每個DiscountStrategy.

4. 總結

主要講了三種模式,只能實例化一個對象的單例模式,能夠存儲和恢復數據的備忘錄模式以及能夠在複雜業務邏輯下替代if else和switch語句的策略模式.

示例代碼

參考:

The Swift Programming Language (Swift 4.1)

Objective-C編程之道

Design Patterns by Tutorials

若有疑問,歡迎留言 :-D

相關文章
相關標籤/搜索