Android 設(shè)計(jì)模式之單例模式

在日常開發(fā)過(guò)程中時(shí)常需要用到設(shè)計(jì)模式,但是設(shè)計(jì)模式有23種,如何將這些設(shè)計(jì)模式了然于胸并且能在實(shí)際開發(fā)過(guò)程中應(yīng)用得得心應(yīng)手呢?和我一起跟著《Android源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)》一書邊學(xué)邊應(yīng)用吧!


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

定義

確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例

使用場(chǎng)景

  • 確保某個(gè)類有且只有一個(gè)對(duì)象的場(chǎng)景,避免產(chǎn)生多個(gè)對(duì)象消耗過(guò)多的資源
  • 某個(gè)類型的對(duì)象只應(yīng)該有一個(gè)

使用例子

  • 應(yīng)用的Application
  • 圖片加載框架對(duì)象,比如我們的ImageLoader,常用的圖片加載框架Glide,universal-image-loader等
  • 數(shù)據(jù)請(qǐng)求管理類,比如可以用一個(gè)類來(lái)統(tǒng)一所有的數(shù)據(jù)請(qǐng)求處理,訪問(wèn)數(shù)據(jù)庫(kù),網(wǎng)絡(luò)請(qǐng)求等,這樣的類肯定只需要一個(gè)實(shí)例

實(shí)現(xiàn)

實(shí)現(xiàn)的要點(diǎn)

  • 構(gòu)造函數(shù)不對(duì)外開放,必須為Private(就是不能用New的形式生成對(duì)象)
  • 通過(guò)一個(gè)靜態(tài)方法或者枚舉返回單例對(duì)象
  • 確保單例類的對(duì)象有且只有一個(gè),尤其是在多線程環(huán)境下
  • 確保單例類對(duì)象在反序列化時(shí)不會(huì)重新創(chuàng)建對(duì)象

常見(jiàn)的實(shí)現(xiàn)方式

餓漢單例模式

public class Singleton {
    private static final Singleton singleton = new Singleton();
    //構(gòu)造函數(shù)私有化
    private Singleton() {
    }
    //公有的靜態(tài)函數(shù),對(duì)外暴露獲取單例對(duì)象的接口
    public static Singleton getInstance() {
        return singleton;
    }
}
  • 餓漢單例模式采用的是靜態(tài)變量 + fianl關(guān)鍵字的方式來(lái)確保單例模式,應(yīng)用啟動(dòng)的時(shí)候就生成單例對(duì)象,效率不高

懶漢模式

public class Singleton {
    private static Singleton singleton;
    //構(gòu)造函數(shù)私有化
    private Singleton() {
    }
    //公有的靜態(tài)函數(shù),對(duì)外暴露獲取單例對(duì)象的接口
    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}
  • 懶漢模式的主要問(wèn)題在于由于加了synchronized關(guān)鍵字,每調(diào)用一次getInstance方法,都會(huì)進(jìn)行同步,造成了不必要的開銷

以上的2種模式用的都不多,了解一下就好,下面介紹平時(shí)用得比較多的單例模式

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

public class Singleton {
    private volatile static Singleton singleton = null;
    //構(gòu)造函數(shù)私有化
    private Singleton() {
    }
    //公有的靜態(tài)函數(shù),對(duì)外暴露獲取單例對(duì)象的接口
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}
  • DCL模式是使用最多的單例模式,它不僅能保證線程安全,資源利用率高,第一次執(zhí)行g(shù)etInstance時(shí)單例對(duì)象才會(huì)實(shí)例化;同時(shí),后續(xù)調(diào)用getInstance方法時(shí)又不會(huì)有懶漢模式的重復(fù)同步的問(wèn)題,效率更高;在絕大多數(shù)情況下都能保證單例對(duì)象的唯一性
  • DCL模式需要注意要用volatile關(guān)鍵字,否則還是會(huì)導(dǎo)致創(chuàng)建多個(gè)實(shí)例
  • DCL模式的缺點(diǎn)是第一次加載時(shí)由于需要同步反應(yīng)會(huì)稍慢;在低于JDK1.5的版本里由于Java內(nèi)存模型的原因有可能會(huì)失效

靜態(tài)內(nèi)部類單例模式

public class Singleton {
    private Singleton() {
    }
    
    public static Singleton getInstance() {
        return SingletonHolder.sInstance;
    }
    
    //靜態(tài)內(nèi)部類
    private static class SingletonHolder {
        private static final Singleton sInstance = new Singleton();
    }
}
  • 第一次加載Singleton類時(shí)不會(huì)初始化sInstance,只有在第一次調(diào)用getInstance方法時(shí)才會(huì)初始化sInstance,延遲了單例對(duì)象的實(shí)例化
  • 靜態(tài)內(nèi)部類單例模式不僅能保證線程安全也能保證單例對(duì)象的唯一性

靜態(tài)內(nèi)部類單例模式和DCL模式是推薦的單例實(shí)現(xiàn)模式

枚舉單例

public enum Singleton {
    INSTANCE;
}
  • 默認(rèn)枚舉實(shí)例的創(chuàng)建是線程安全的,并且在任何情況下它都是一個(gè)單例
  • 其他的單例模式,在一種情況下會(huì)出現(xiàn)失效的情況——反序列化,但是枚舉即使在反序列化情況下也不會(huì)失效

總結(jié)

  • 單例模式是運(yùn)用頻率很高的模式,由于在客戶端一般沒(méi)有高并發(fā)的情況,現(xiàn)在的JDK版本也已經(jīng)到了9了,一般推薦用DCL模式和靜態(tài)內(nèi)部類2種實(shí)現(xiàn)。
  • 單例對(duì)象的生命周期很長(zhǎng),如果持有Context,很容易引發(fā)內(nèi)存泄漏,所以傳遞給單例對(duì)象的Context最好是Application Context

最后加點(diǎn)福利

  • 單例模式的代碼格式都是固定的,每次都要那么寫有點(diǎn)麻煩,咱們可以用添加模板的方法來(lái)偷懶,詳情見(jiàn)圖。
添加單例模式的模板
  • 添加了模板后,在需要實(shí)現(xiàn)單例模式的類里面直接輸入你的模板名字,如圖中的sin, Android Studio就會(huì)出現(xiàn)提示,回車搞定!趕緊試試吧!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一.什么是單例模式 單例模式的定義:確保一個(gè)類只有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)他的全局訪問(wèn)點(diǎn)。單例模式是幾個(gè)設(shè)計(jì)模式中...
    Geeks_Liu閱讀 2,327評(píng)論 0 10
  • 概述 單例模式是應(yīng)用最廣的模式之一,在應(yīng)用這個(gè)模式時(shí),單例對(duì)象的類必須保證只有一個(gè)實(shí)例存在。許多時(shí)候整個(gè)系統(tǒng)只需要...
    劉滌生閱讀 1,094評(píng)論 0 5
  • 定義 確保某個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。 應(yīng)用場(chǎng)景 確保某個(gè)類有且只有一個(gè)對(duì)象的場(chǎng)景...
    Utte閱讀 580評(píng)論 0 0
  • 目錄 定義 使用場(chǎng)景 UML類圖 實(shí)現(xiàn)方式 餓漢式 懶漢式 Double Check LockDCL雙重檢查鎖 靜...
    喵了個(gè)嗚s閱讀 3,956評(píng)論 1 12
  • 作者:ivm 之前做android 項(xiàng)目時(shí),用的最多的就是設(shè)計(jì)模式,就是單例模式,用的時(shí)候,心里總有些疑問(wèn)。今天呢...
    lovesosoi閱讀 12,192評(píng)論 12 18

友情鏈接更多精彩內(nèi)容