單例模式(Adapter Pattern)
一.什么是單例模式:
確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。
二.單例模式的優(yōu)點(diǎn):
1.由于單例模式在內(nèi)存中只有一個(gè)實(shí)例,減少了內(nèi)存開支,特別是一個(gè)對(duì)象需要頻繁的創(chuàng)建、銷毀時(shí),而且創(chuàng)建或銷毀時(shí)性能又無法優(yōu)化,單例模式的優(yōu)勢(shì)就非常明顯。
2.由于單例模式模式只生成一個(gè)實(shí)例,所以減少了系統(tǒng)的性能開銷,當(dāng)一個(gè)對(duì)象的產(chǎn)生需要比較多的資源時(shí),如讀取配置、產(chǎn)生其他依賴對(duì)象時(shí),則可以通過在應(yīng)用啟動(dòng)時(shí)直接產(chǎn)生一個(gè)單例對(duì)象,然后用永久駐留內(nèi)存的方式來解決。
3.單例模式可以避免對(duì)資源的多重占用,例如一個(gè)寫文件動(dòng)作,由于只有一個(gè)實(shí)例存在內(nèi)存中,避免對(duì)同一個(gè)資源文件的同時(shí)寫操作。
4.單例模式可以在系統(tǒng)設(shè)置全局的訪問點(diǎn),優(yōu)化和共享資源訪問。
三.單例模式的缺點(diǎn):
1.擴(kuò)展困難
2.對(duì)測(cè)試不利
3.與單一職責(zé)原則有沖突
四.單例模式的適用情況:
1.要求生成唯一序列號(hào)的環(huán)境
2.在這個(gè)項(xiàng)目中需要一個(gè)共享訪問點(diǎn)或共享數(shù)據(jù)
3.創(chuàng)建一個(gè)對(duì)象需要消耗的資源過多(如訪問IO和數(shù)據(jù)庫(kù)等資源)
4.需要定義大量的靜態(tài)常量和靜態(tài)方法的環(huán)境
五.Swift實(shí)現(xiàn)單例模式的方式:
1.設(shè)置一個(gè)靜態(tài)實(shí)例變量
2.初始化方法設(shè)為私有
class Singleton {
static let sharedInstance = Singleton()
private init(){
}
}
六.單例模式的讀取線程安全:
由于單例是全局的,可以在多個(gè)地方同時(shí)調(diào)用。如果多個(gè)線程同時(shí)調(diào)用單例某個(gè)屬性的set和get方法,可能會(huì)get到一個(gè)錯(cuò)誤值,這個(gè)時(shí)候應(yīng)該如何處理呢?
1.使用同步隊(duì)列:
class Singleton {
private let serialQueue = DispatchQueue(label:"SerialQueue")
private var queueDic = [String: String]()
static let sharedInstance = Singleton()
private init(){
}
func setDicValue(value: String, for key: String){
serialQueue.sync {
self.queueDic[key] = value
}
}
func getDicValue(for key: String) -> String? {
var result: String?
serialQueue.sync {
result = queueDic[key]
}
return result
}
}
2.使用異步隊(duì)列:
class Singleton {
private let concurrentQueue = DispatchQueue(label: "ConcurrentQueue", attributes: .concurrent, target: nil)
private var queueDic = [String: String]()
static let sharedInstance = Singleton()
private init(){
}
func setDicValue(value: String, for key: String){
concurrentQueue.async(flags: .barrier) {
self.queueDic[key] = value
}
}
func getDicValue(for key: String) -> String? {
var result: String?
concurrentQueue.sync {
result = queueDic[key]
}
return result
}
}
這里使用柵欄函數(shù)的目的:
demo地址:Singleton Pattern