單例模式(Singletion)

單例模式(Singletion),我估計大家用到比較多.我使用的第一個設計模式就是單利模式.

單例模式是爲了確保一個類有且僅有一個實例,併爲它提供一個全局訪問點.簡單說就是你不能new一個實例出來.


舉一個例子,比如在我的開發中有這樣一種情況,我們有同事寫了一組地圖工具MapUtils.java,我們在不同的使用地方來調用這個工具類,爲了避免有多個工具類實例存在就使用單利模式.

一、懶漢單利模式模式

public class MapUtils {

    private MKSearch           mkSearch;
    private LocationClient     locationClient;
    private OnLocationListener listener;

    private static MapUtils    instance;

    private MapUtils() {
    }

    public static MapUtils getInstance(Context context) {
        if (null == instance) {
            instance = new MapUtils(context.getApplicationContext());
        }
        return instance;
    }
}

構造函數爲private,這樣就不能使用new來創建實例.唯一實例只能通過getInstance()方法訪問。(事實上,通過Java反射機制是能夠實例化構造方法爲private的類的,那基本上會使所有的Java單例實現失效。此問題在此處不做討論.)

上面的單例模式爲懶漢單例模式,懶漢式單例的實現沒有考慮線程安全問題,它是線程不安全的,併發環境下很可能出現多個MapUtils實例,要實現線程安全,有以下三種方式,都是對getInstance這個方法改造,保證了懶漢式單例的線程安全,如果你第一次接觸單例模式,對線程安全不是很瞭解,可以先跳過下面這三小條,去看餓漢式單例,等看完後面再回頭考慮線程安全的問題.

1、在getInstance方法上加同步

public static synchronized MapUtils getInstance(Context context) {  
    if (null == instance) {    
        instance = new MapUtils(context.getApplicationContext());
    }    
    return instance;  
}

2、雙重檢查鎖定

public static MapUtils getInstance(Context context) {
    if (null == instance) {
        synchronized (MapUtils.class) {
            if (null == instance) {
                instance = new MapUtils(context.getApplicationContext());
            }
        }
    }
    return instance;
}

3、靜態內部類

public class MapUtils {
    private static class LazyHolder {
        private static Context context;
        private static final MapUtils INSTANCE = new MapUtils(context.getApplicationContext());
    }
    private MapUtils(Context context){}
    public static final MapUtils getInstance(Context context) {
        LazyHolder.context = context;
        return LazyHolder.INSTANCE;
    }
}  

二、餓漢式單例模式

//餓漢式單例類.在類初始化時,已經自行實例化

public class MapUtils {  
    private MapUtils() {}  
    private static final MapUtils instance = new MapUtils();  
    //靜態工廠方法   
    public static MapUtils getInstance() {  
        return instance;  
    }  
}  

餓漢式在類創建的同時就已經創建好一個靜態的對象供系統使用,以後不再改變,所以天生是線程安全的。
還有一種登記式單例模式.沒有細細去看就不做介紹了.


什麼是線程安全?
如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的。
或者說:一個類或者程序所提供的接口對於線程來說是原子操作,或者多個線程之間的切換不會導致該接口的執行結果存在二義性,也就是說我們不用考慮同步的問題,那就是線程安全的。


PS:對於設計模式我只是作爲學習筆記來寫的,並非網上大牛們的手筆,所以各位看官看看就行,有錯誤請多多指正,要真正學習設計模式,書籍有,《大話設計模式》,這個需要C++語言底子,《您的設計模式》這個講解的很有風趣,沒有《大話設計模式》講解的深,還有一本《Head First 設計模式》也講解的蠻有意思的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章