“Android設(shè)計(jì)模式”這個(gè)系列主要是對Android項(xiàng)目中的設(shè)計(jì)模式進(jìn)行分析總結(jié),學(xué)習(xí)自《Android 源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)》,錯(cuò)誤之處煩請指正~
Android設(shè)計(jì)模式系列文章:
1、詳解 - 單例模式
2宪赶、詳解 - Builder模式
一宗弯、 概述
1.1 定義
確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例搂妻。
1.2 使用場景
確保某個(gè)類有且只有一個(gè)對象的場景蒙保,避免產(chǎn)生多個(gè)對象消耗過多的資源;或者某種類型的對象應(yīng)該有且只有一個(gè)欲主。
eg:創(chuàng)建一個(gè)對象需要消耗的資源過多追他,如訪問IO和數(shù)據(jù)庫資源。
1.3 關(guān)鍵點(diǎn)
- 構(gòu)造函數(shù)不對外開放岛蚤,一般為
private
邑狸; - 通過一個(gè)靜態(tài)方法或者枚舉返回單例類對象;
- 確保單例類的對象有且只有一個(gè)涤妒,尤其是在
多線程
環(huán)境下单雾; - 確保單例類對象在反序列化時(shí)不會重新構(gòu)建對象。
二她紫、實(shí)現(xiàn)方式
2.1 懶漢模式
聲明一個(gè)靜態(tài)對象硅堆,并且在用戶第一次調(diào)用 getInstance
時(shí)進(jìn)行初始化。
2.1.1 分析
synchronized
關(guān)鍵字用于在多線程情況下保證單例對象唯一性優(yōu)點(diǎn):單例只有在使用時(shí)才會被實(shí)例化贿讹,在一定程度上節(jié)約了資源
-
缺點(diǎn):
- 每一次加載時(shí)需要及時(shí)進(jìn)行實(shí)例化渐逃,響應(yīng)速度稍慢
- 每次調(diào)用
getInstance()
都進(jìn)行同步,造成不必要的同步開銷
一般不建議使用
2.1.2 源碼
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (null == instance) {
instance = new Singleton();//加載時(shí)進(jìn)行實(shí)例化
}
return instance;
}
}
2.2 餓漢模式
聲明靜態(tài)對象時(shí)就已經(jīng)初始化民褂。
2.2.1 分析
靜態(tài)對象在聲明的時(shí)候就已經(jīng)初始化茄菊,從而保證了單例對象唯一性
優(yōu)點(diǎn): 每次調(diào)用
getInstance()
直接取出靜態(tài)對象疯潭,不需要同步鎖,響應(yīng)速度快缺點(diǎn):初始化聲明對象造成了一定資源的閑置浪費(fèi)
2.2.2 源碼
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
2.3 Double Check Lock (DCL) 模式
2.3.1 分析
-
優(yōu)點(diǎn):
- 資源利用率高
- 既能夠在需要時(shí)才初始化單例面殖,又能夠保證線程安全竖哩,且單例對象初始化后調(diào)用
getInstance()
不進(jìn)行同步鎖
-
缺點(diǎn):
- 第一次加載時(shí)響應(yīng)稍慢
- 由于Java內(nèi)存模型的原因偶爾會失敗
-
instance = new Singleton();
這句代碼并不是一個(gè)原子操作,由于Java
編譯器允許處理器亂序執(zhí)行匯編指令以及JDK1.5
之前的JVM (Java Memory Model, Java 內(nèi)存模型)
中Cache脊僚、寄存器到主內(nèi)存回寫順序的規(guī)定相叁,該語句轉(zhuǎn)換的匯編指令無法確保順序執(zhí)行 - 在
JDK1.5
之后,具體化了volatile
關(guān)鍵字辽幌,因此可以直接定義成private volatile static Singleton instance = null;
增淹,就可以保證instance
對象每次都是從主內(nèi)存中讀取
-
2.3.2 源碼
public class Singleton {
private volatile static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}
2.4 靜態(tài)內(nèi)部類單例模式
2.4.1 分析
強(qiáng)烈推薦使用
-
優(yōu)點(diǎn):
- 第一次加載
Singleton
類時(shí)并不會初始化instance
,只有在第一次調(diào)用getInstance()
時(shí)才會初始化 - 既能保證線程安全乌企,也能保證單例對象的唯一性埠通,同時(shí)也延遲了單例的實(shí)例化
- 第一次加載
2.4.2 源碼
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
/**
* 靜態(tài)內(nèi)部類
*/
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
}
2.5 枚舉單例
2.5.1 分析
枚舉單例模式最大的優(yōu)點(diǎn)是寫法簡單,枚舉在 Java
中與普通類是一樣的逛犹,不僅能夠有字段端辱,還能夠有自己的方法。最重要的是默認(rèn)枚舉實(shí)例的創(chuàng)建時(shí)線程安全的虽画,并且在任何情況下它都是一個(gè)單例舞蔽。
在上述的幾種單例模式中,反序列化 的時(shí)候會出現(xiàn)重新創(chuàng)建對象的情況码撰。**
上述示例中如果要杜絕單利對象在被反序列化時(shí)重新生成對象渗柿,則必須加入如下方法:
private Object readResolve() throws ObjectStreamException {
return instance;
}
2.5.2 源碼
public enum Singleton {
INSTANCE;
public void doSomething() {
// ... do something
}
}
2.6 使用容器實(shí)現(xiàn)單例模式
2.6.1 分析
在程序初始化的時(shí)候,將多種單例類型注入到一個(gè)統(tǒng)一的管理類中脖岛,在使用時(shí)根據(jù) key
獲取對象對應(yīng)類型的對象朵栖。
這種方式使得我們可以管理多種類型的單例,并且在使用時(shí)候可以通過統(tǒng)一的接口進(jìn)行獲取操作柴梆,降低了用戶的使用成本陨溅,也對用戶隱藏了具體實(shí)現(xiàn),降低了耦合度绍在。
2.6.2 源碼
public class SingletonManager {
private static Map<String, Object> data = new HashMap<>();
public SingletonManager() {
}
public static void register(String key, Object instance) {
if (!data.containsKey(key)) {
data.put(key, instance);
}
}
public static Object get(String key) {
return data.get(key);
}
}
三门扇、小結(jié)
所有的單例模式核心原理都是將構(gòu)造函數(shù)私有化,并且通過靜態(tài)方法獲取一個(gè)唯一的實(shí)例偿渡。
需要注意的是在獲取實(shí)例的過程中保證線程安全臼寄、防止反序列化導(dǎo)致重新生成實(shí)例對象等問題。
具體選擇哪種方式實(shí)現(xiàn)單例模式還需要結(jié)合項(xiàng)目業(yè)務(wù)邏輯溜宽。
本文對 單例模式 的分析到此就結(jié)束了吉拳,部分內(nèi)容學(xué)習(xí)自 《Android源碼設(shè)計(jì)模式 解析與實(shí)戰(zhàn)》。