設(shè)計模式(Design pattern)是一套被反復(fù)使用让腹、多數(shù)人知曉的焦读、經(jīng)過分類編目的仓蛆、代碼設(shè)計經(jīng)驗的總結(jié)。GoF提出了23種設(shè)計模式蝌诡,本系列將使用Swift語言來實現(xiàn)這些設(shè)計模式
概述
通過共享已存在的對象溉贿,減少創(chuàng)建對象內(nèi)存開銷的設(shè)計模式被稱作享元模式
享元模式Flyweight
和單例模式Singleton
像是一對孿生兄弟,二者的表現(xiàn)方式非常相似浦旱,但二者的存在目的卻不一樣:
-
單例模式
保證了整個應(yīng)用聲明周期內(nèi)顽照,同一個對象只會存在一份內(nèi)存,并且任何時間都能被訪問使用。
-
享元模式
如果存在可以復(fù)用的對象代兵,那么對象將被共享而不是創(chuàng)建新的對象
在iOS開發(fā)中尼酿,享元模式的最佳實踐就是UITableView
的復(fù)用機制——超出屏幕外的單元格統(tǒng)一被回收放到一個復(fù)用隊列之中,等待著需要新的單元格時進行復(fù)用植影。
實戰(zhàn)
筆者最近項目有一個需求裳擎,幾乎所有的數(shù)據(jù)都要保存在本地。由于應(yīng)用的特殊性思币,模塊之間需要用到彼此的數(shù)據(jù)鹿响,如果使用單例模式來做,那么同一時間占用的內(nèi)存是非常的大的谷饿,因此以享元模式的思想封裝了一個數(shù)據(jù)管理類:
class DataManager {
//MARK: - Variable
private static var shareStorage = [String: AnyObject]()
private var storeKey = "DefaultKey"
private var storeData = [AnyObject]()
var data: [AnyObject] {
get {
return storeData
}
}
//MARK: - Operate
func insert(data: AnyObject) { }
func delete(at index: Int) { }
func save() { }
}
筆者以數(shù)據(jù)模型的類名作為數(shù)據(jù)管理的關(guān)鍵字惶我,因此創(chuàng)建一個私有的靜態(tài)字典用來保存當(dāng)前正在使用的數(shù)據(jù)。由于數(shù)據(jù)以加密的方式存儲在沙盒目錄下博投,在數(shù)據(jù)量足夠大的時候绸贡,從本地讀取這些數(shù)據(jù)會占用大量的花銷,因此在數(shù)據(jù)管理對象被創(chuàng)建的時候需要判斷是否存在可復(fù)用的數(shù)據(jù)毅哗,如果不存在再從本地加載:
class DataManager {
init() {
initalizeData()
}
init(storeKey: String) {
self.storeKey = storeKey
initalizeData()
}
private func initalizeData() {
if let data = DataManager.shareStorage[storeKey] {
storeData = data as! [AnyObject]
} else {
loadData()
DataManager.shareStorage[storeKey] = storeData as AnyObject?
}
}
private func loadData() {
// load data from local path
}
}
ok听怕,對于數(shù)據(jù)的復(fù)用已經(jīng)完成了,剩下的問題是不可能讓字典一直存儲這些數(shù)據(jù)虑绵,否則直接使用單例要更加方便的多尿瞭。對此,筆者使用了計數(shù)功能翅睛,保證數(shù)據(jù)可以在沒有使用的時候進行本地存儲然后釋放:
class DataManager {
deinit {
let count = DataManager.shareStorage[countKey()] as! Int
if count == 1 {
save()
DataManager.shareStorage[storeKey] = nil
} else {
DataManager.shareStorage[countKey()] = (count - 1) as AnyObject?
}
}
private func initalizeData() {
if let data = DataManager.shareStorage[storeKey] {
let count = DataManager.shareStorage[countKey()] as! Int
DataManager.shareStorage[countKey()] = (count + 1) as AnyObject?
storeData = data as! [AnyObject]
} else {
loadData()
DataManager.shareStorage[countKey()] = 1 as AnyObject
DataManager.shareStorage[storeKey] = storeData as AnyObject?
}
}
private func countKey() -> String {
return "\(storeKey)Count"
}
}
上面的代碼是初步的邏輯搭建声搁,下一步還需要考慮線程安全等其他問題,這里就不再寫出來了
總結(jié)
最開始接觸享元模式概念的時候捕发,筆者是有些混亂的疏旨,也不清楚它和單例的區(qū)別。簡單來說爬骤,這是一種提供了一種擁有單例優(yōu)點、以及改善了一部分單例缺點的設(shè)計模式莫换,但是享元模式更加的復(fù)雜霞玄,在考慮到多線程的環(huán)境下,數(shù)據(jù)競爭要比單例激烈的多拉岁,也危險的多坷剧。