Android中單例模式

設計模式系列:
        0. Android開發常用設計模式;

        1. Android中單例模式;

        2. Android中建造者(builder)模式;

        3. Android中觀察者模式;

        4. Android中原型模式;

        5. Android中策略模式;

        6. Android中工廠模式;

        7. Android中代理模式;

        8. Android中裝飾者模式;

        9. Android中適配器模式;


單利模式定義:核心結構中只包含一個被稱爲單例的特殊類。通過單例模式可以保證系統中一個類只有一個實例。即一個類只有一個對象實例。

一、常見需求場景


  三毛:“小白,你對後臺返回來的json數據解析是用json還是Gson吖”

  小白:我是用的Gson解析後臺返回來的數據,怎麼了?


二、基本解決方法


  三毛:“那你是怎樣使用Gson的呢”

  小白:因爲我一般都是拿到後臺給的json字符串數據,然後轉換成實體類對象,就像下面拿到json字符串jsonStr,然後轉換成實體類A

 //初生牛犢不怕虎的(普通寫法)
 Gson gson = new Gson();
 A aBean = gson.fromJson(jsonStr, A.class);


三、基本解決方法存在的問題


  三毛:“我的白,你這樣new,new,new,一兩個沒啥問題,但是幾十個,幾百個,會存在內存佔用多和不同對象對同一個資源的操作的問題波”

  小白:毛毛哥說得是,確實是這樣,那我給Gson寫一個類,然後調用它來解析,像下面那樣

//餓漢式單例寫法
public class GsonSingle {

    private static Gson mGson = new Gson();
    private GsonSingle() {//構造函數設置爲private,防止外部程序通過new來構造
    }
    public static Gson getInstance() {
        return mGson;
    }

}

//調用gson單利類來解析
 A aBean = GsonSingle.getInstance().fromJson(jsonStr, A.class);

  三毛:”白啊,你這樣確實解決了一直new,new,new的問題,假設你這個GsonSingle類不使用getInstance靜態方法的時候,而是使用其他靜態方法,那你靜new出來的靜態實例不就浪費內存資源了嘛”

  小白:啪啪啪(敲鍵盤這裏寫圖片描述),我改成下面那樣子,毛毛哥看看這下Ok了吧

//懶漢式寫法
public class GsonSingle {

    private static Gson mGson = null;

    private GsonSingle() {
    }

    public static Gson getInstance() {
        if (mGson == null) {
            mGson = new Gson();
        }
        return mGson;
    }
}

  三毛:“你這樣寫,正常來看是沒什麼問題,但是在多線程的情況下就會出現另外的問題,多線程併發,線程不安全的情況呢”;

  小白:那我給它加個鎖synchronized,變成下面那樣子,怎麼樣,這下沒什麼好說的了吧;

//懶漢式枷鎖寫法
public class GsonSingle {

    private static Gson mGson = null;

    public static synchronized Gson getInstance() {
        if (mGson == null) {
            mGson = new Gson();
        }
        return mGson;
    }

}

  三毛:“嘿嘿,這樣加鎖確實處理了多線程併發的問題,但是當你次次獲取單例都同步,那不和前面一樣,造成資源浪費了嗎,也就是說等於沒啥子改進的啵”

  小白:有點道理,啪啪啪(敲鍵盤),好了,調下位置,改成下面那樣,這樣一來就不會次次都因爲同步造成資源浪費了吧

//懶漢式雙重枷鎖寫法
public class GsonSingle {
    private static Gson mGson = null;
    private GsonSingle() {
    }

    public static Gson getInstance() {
        //先檢查實例是否存在,如果不存在才進入下面的同步塊
        if(mGson == null){
            //同步塊,線程安全地創建實例
            synchronized(Gson.class){
                //再次檢查實例是否存在,如果不存在才真正地創建實例
                if(mGson == null){
                    mGson = new Gson();
                }
            }
        }
        return mGson;
    }
}

  三毛:“嗯,是的,不過你這樣寫第一次加載類的時候還是需要同步,也就意味着第一次加載類會犧牲一點時間,你覺得還能改進嘛”

  小白:我想不到其他改進的辦法了

  三毛:“嘿嘿嘿,可能你一時忘記了,其實可以用內部類來寫單例,像下面這樣”

//內部類單例寫法
public class GsonSingle {
    private GsonSingle() {
    }

    public static Gson getInstance() {
        return GsonSingleHolder.gson;
    }

    private static class GsonSingleHolder {
        private static final Gson gson = new Gson();
    }
}

  小白:握草,居然還有這種操作,三毛哥,你平常的單例都是用這中內部類的方式嗎?

  三毛:“大部分都是用的內部類寫單例,也有時候偷懶,像你第一種方式直接在類裏new一個靜態對象,不過我還是看情況來選擇,另外你上面的改進也是屬於單例設計模式中的幾種寫法,其實還有網絡江湖上流傳的另外2中寫法你可能沒想到,那就是枚舉單例和容器單例”

  小白:嗷嗷嗷,和毛毛哥聊天又學到東西了,我看看枚舉單例和容器單例去~~


四、單例模式和普通寫法的區別


  1.一個類只有一個實例
  2.自己創建這個實例
  3.整個系統只能用這個實例
  4.內存開銷減少了,降低多個對象訪問同一個資源造成併發問題情況

發佈了35 篇原創文章 · 獲贊 33 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章