Android 設計模式之單例模式

在平常開發過程當中時常須要用到設計模式,可是設計模式有23種,如何將這些設計模式瞭然於胸而且能在實際開發過程當中應用得駕輕就熟呢?和我一塊兒跟着《Android源碼設計模式解析與實戰》一書邊學邊應用吧!

設計模式系列文章


今天咱們要講的是單例模式

定義

確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例git

使用場景

  • 確保某個類有且只有一個對象的場景,避免產生多個對象消耗過多的資源
  • 某個類型的對象只應該有一個

使用例子

  • 應用的Application
  • 圖片加載框架對象,好比咱們的ImageLoader,經常使用的圖片加載框架Glide,universal-image-loader等
  • 數據請求管理類,好比能夠用一個類來統一全部的數據請求處理,訪問數據庫,網絡請求等,這樣的類確定只須要一個實例

實現

實現的要點

  • 構造函數不對外開放,必須爲Private(就是不能用New的形式生成對象)
  • 經過一個靜態方法或者枚舉返回單例對象
  • 確保單例類的對象有且只有一個,尤爲是在多線程環境下
  • 確保單例類對象在反序列化時不會從新建立對象

常見的實現方式

餓漢單例模式

public class Singleton {
    private static final Singleton singleton = new Singleton();
    //構造函數私有化
    private Singleton() {
    }
    //公有的靜態函數,對外暴露獲取單例對象的接口
    public static Singleton getInstance() {
        return singleton;
    }
}
複製代碼
  • 餓漢單例模式採用的是靜態變量 + fianl關鍵字的方式來確保單例模式,應用啓動的時候就生成單例對象,效率不高

懶漢模式

public class Singleton {
    private static Singleton singleton;
    //構造函數私有化
    private Singleton() {
    }
    //公有的靜態函數,對外暴露獲取單例對象的接口
    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}
複製代碼
  • 懶漢模式的主要問題在於因爲加了synchronized關鍵字,每調用一次getInstance方法,都會進行同步,形成了沒必要要的開銷

以上的2種模式用的都很少,瞭解一下就好,下面介紹平時用得比較多的單例模式github

Double Check Lock(DCL)模式(雙重檢查鎖定模式)

public class Singleton {
    private volatile static Singleton singleton = null;
    //構造函數私有化
    private Singleton() {
    }
    //公有的靜態函數,對外暴露獲取單例對象的接口
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}
複製代碼
  • DCL模式是使用最多的單例模式,它不只能保證線程安全,資源利用率高,第一次執行getInstance時單例對象纔會實例化;同時,後續調用getInstance方法時又不會有懶漢模式的重複同步的問題,效率更高;在絕大多數狀況下都能保證單例對象的惟一性
  • DCL模式須要注意要用volatile關鍵字,不然仍是會致使建立多個實例
  • DCL模式的缺點是第一次加載時因爲須要同步反應會稍慢;在低於JDK1.5的版本里因爲Java內存模型的緣由有可能會失效

靜態內部類單例模式

public class Singleton {
    private Singleton() {
    }
    
    public static Singleton getInstance() {
        return SingletonHolder.sInstance;
    }
    
    //靜態內部類
    private static class SingletonHolder {
        private static final Singleton sInstance = new Singleton();
    }
}
複製代碼
  • 第一次加載Singleton類時不會初始化sInstance,只有在第一次調用getInstance方法時纔會初始化sInstance,延遲了單例對象的實例化
  • 靜態內部類單例模式不只能保證線程安全也能保證單例對象的惟一性

靜態內部類單例模式和DCL模式是推薦的單例實現模式數據庫

枚舉單例

public enum Singleton {
    INSTANCE;
}
複製代碼
  • 默認枚舉實例的建立是線程安全的,而且在任何狀況下它都是一個單例
  • 其餘的單例模式,在一種狀況下會出現失效的狀況——反序列化,可是枚舉即便在反序列化狀況下也不會失效

總結

  • 單例模式是運用頻率很高的模式,因爲在客戶端通常沒有高併發的狀況,如今的JDK版本也已經到了9了,通常推薦用DCL模式和靜態內部類2種實現。
  • 單例對象的生命週期很長,若是持有Context,很容易引起內存泄漏,因此傳遞給單例對象的Context最好是Application Context

最後加點福利

  • 單例模式的代碼格式都是固定的,每次都要那麼寫有點麻煩,我們能夠用添加模板的方法來偷懶,詳情見圖。

添加單例模式的模板

  • 添加了模板後,在須要實現單例模式的類裏面直接輸入你的模板名字,如圖中的sin, Android Studio就會出現提示,回車搞定!趕忙試試吧!

源碼地址:https://github.com/snowdream1314/DesignPatternsExamples設計模式


歡迎關注個人微信公衆號,和我一塊兒學習一塊兒成長! 安全

AntDream
相關文章
相關標籤/搜索