設計模式系列:
0. 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.內存開銷減少了,降低多個對象訪問同一個資源造成併發問題情況。