前言
Android的設計模式系列文章介紹:歡迎關注,持續更新中:
Android的設計模式-設計模式的六大原則
一句話總結23種設計模式則
創建型模式:
Android的設計模式-單例模式
Android的設計模式-建造者模式
Android的設計模式-工廠方法模式
Android的設計模式-簡單工廠模式
Android的設計模式-抽象工廠模式
Android的設計模式-原型模式
行為型模式:
Android的設計模式-策略模式
Android的設計模式-狀態模式
Android的設計模式-責任鏈模式
Android的設計模式-觀察者模式
Android的設計模式-模板方法模式
Android的設計模式-迭代器模式
Android的設計模式-備忘錄模式
Android的設計模式-訪問者模式
Android的設計模式-中介者模式
Android的設計模式-解釋器模式
Android的設計模式-命令模式
結構型模式:
Android的設計模式-代理模式
Android的設計模式-組合模式
Android的設計模式-適配器模式
Android的設計模式-裝飾者模式
Android的設計模式-享元模式
Android的設計模式-外觀模式
Android的設計模式-橋接模式
1.定義
確保某個類只有一個實例,并且自行實例化并向整個系統提供這個實例。
2.介紹
單例模式屬于創建類模式。
單例模式有以下特點:
1. 單例類只能有一個實例。
2. 單例類必須自己創建自己的唯一實例。
3. 單例類必須給所有其他對象提供這一實例。
3.實現
3.4 餓漢式
//單例類.
public class Singleton {
private Singleton() {//構造方法為private,防止外部代碼直接通過new來構造多個對象
}
private static final Singleton single = new Singleton(); //在類初始化時,已經自行實例化,所以是線程安全的。
public static Singleton getInstance() { //通過getInstance()方法獲取實例對象
return single;
}
}
- 優點:寫法簡單,線程安全。
- 缺點:沒有懶加載的效果,如果沒有使用過的話會造成內存浪費。
3.1 懶漢式(線程不安全)
//單例類
public class Singleton {
private Singleton() {
}
private static Singleton single = null;
public static Singleton getInstance() {
if (single == null) {
single = new Singleton(); //在第一次調用getInstance()時才實例化,實現懶加載,所以叫懶漢式
}
return single;
}
}
- 優點:實現了懶加載的效果。
- 缺點:線程不安全。
3.1 懶漢式(線程安全)
//單例類
public class Singleton {
private Singleton() {
}
private static Singleton single = null;
public static synchronized Singleton getInstance() { //加上synchronized同步
if (single == null) {
single = new Singleton();
}
return single;
}
}
- 優點:實現了懶加載的效果,線程安全。
- 缺點:使用synchronized會造成不必要的同步開銷,而且大部分時候我們是用不到同步的。
3.3 雙重檢查鎖定(DCL)
public class Singleton {
private volatile static Singleton singleton; //volatile 能夠防止代碼的重排序,保證得到的對象是初始化過
private Singleton() {
}
public static Singleton getSingleton() {
if (singleton == null) { //第一次檢查,避免不必要的同步
synchronized (Singleton.class) { //同步
if (singleton == null) { //第二次檢查,為null時才創建實例
singleton = new Singleton();
}
}
}
return singleton;
}
}
- 優點:懶加載,線程安全,效率較高
- 缺點:volatile影響一點性能,高并發下有一定的缺陷,某些情況下DCL會失效,雖然概率較小。
3.5 靜態內部類
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
//第一次調用getInstance方法時才加載SingletonHolder并初始化sInstance
return SingletonHolder.sInstance;
}
//靜態內部類
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
- 優點:懶加載,線程安全,推薦使用
3.6 枚舉單例
public enum Singleton {
INSTANCE; //定義一個枚舉的元素,它就是Singleton的一個實例
public void doSomething() {
}
}
- 優點:線程安全,寫法簡單,能防止反序列化重新創建新的對象。
- 缺點:可讀性不高,枚舉會比靜態常量多那么一丁點的內存。
3.7 使用容器實現單例模式
//單例管理類
public class SingletonManager {
private static Map<String, Object> objMap = new HashMap<String, Object>();
public static void registerService(String key, Object instance) {
if (!objMap.containsKey(key)) {
objMap.put(key, instance);//添加單例
}
}
public static Object getService(String key) {
return objMap.get(key);//獲取單例
}
}
- 優點:方便管理。
- 缺點:寫法稍復雜。
4.注意事項
- 使用反射能夠破壞單例模式,所以應該慎用反射
Constructor con = Singleton.class.getDeclaredConstructor();
con.setAccessible(true);
// 通過反射獲取實例
Singleton singeton1 = (Singleton) con.newInstance();
Singleton singeton2 = (Singleton) con.newInstance();
System.out.println(singeton1==singeton2);//結果為false,singeton1和singeton2將是兩個不同的實例
- 可以通過當第二次調用構造函數時拋出異常來防止反射破壞單例,以懶漢式為例:
public class Singleton {
private static boolean flag = true;
private static Singleton single = null;
private Singleton() {
if (flag) {
flag = !flag;
} else {
throw new RuntimeException("單例模式被破壞!");
}
}
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
- 反序列化時也會破壞單例模式,可以通過重寫readResolve方法避免,以餓漢式為例:
public class Singleton implements Serializable {
private Singleton() {
}
private static final Singleton single = new Singleton();
public static Singleton getInstance() {
return single;
}
private Object readResolve() throws ObjectStreamException {//重寫readResolve()
return single;//直接返回單例對象
}
}
5.應用場景
- 頻繁訪問數據庫或文件的對象。
- 工具類對象;
- 創建對象時耗時過多或耗費資源過多,但又經常用到的對象;
6.優點
- 內存中只存在一個對象,節省了系統資源。
- 避免對資源的多重占用,例如一個文件操作,由于只有一個實例存在內存中,避免對同一資源文件的同時操作。
7.缺點
- 獲取對象時不能用new
- 單例對象如果持有Context,那么很容易引發內存泄露。
- 單例模式一般沒有接口,擴展很困難,若要擴展,只能修改代碼來實現。
相關文章閱讀
Android的設計模式-設計模式的六大原則
一句話總結23種設計模式則
創建型模式:
Android的設計模式-單例模式
Android的設計模式-建造者模式
Android的設計模式-工廠方法模式
Android的設計模式-簡單工廠模式
Android的設計模式-抽象工廠模式
Android的設計模式-原型模式
行為型模式:
Android的設計模式-策略模式
Android的設計模式-狀態模式
Android的設計模式-責任鏈模式
Android的設計模式-觀察者模式
Android的設計模式-模板方法模式
Android的設計模式-迭代器模式
Android的設計模式-備忘錄模式
Android的設計模式-訪問者模式
Android的設計模式-中介者模式
Android的設計模式-解釋器模式
Android的設計模式-命令模式
結構型模式:
Android的設計模式-代理模式
Android的設計模式-組合模式
Android的設計模式-適配器模式
Android的設計模式-裝飾者模式
Android的設計模式-享元模式
Android的設計模式-外觀模式
Android的設計模式-橋接模式