
定義
單例模式最初的定義出現(xiàn)于《設(shè)計(jì)模式》(艾迪生維斯理, 1994):“保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)?!?/p>
而我對(duì)單例的理解是,在可控的范圍內(nèi)充當(dāng)全局變量的作用,就相當(dāng)于C語言中一個(gè)全局結(jié)構(gòu)體。
一些資源管理器常常設(shè)計(jì)成單例模式。在計(jì)算機(jī)系統(tǒng)中,需要管理的資源包括軟件外部資源,譬如每臺(tái)計(jì)算機(jī)可以有若干個(gè)打印機(jī),但只能有一個(gè)Printer Spooler, 以避免兩個(gè)打印作業(yè)同時(shí)輸出到打印機(jī)中。每臺(tái)計(jì)算機(jī)可以有若干傳真卡,但是只應(yīng)該有一個(gè)軟件負(fù)責(zé)管理傳真卡,以避免出現(xiàn)兩份傳真作業(yè)同時(shí)傳到傳真卡中的情況。每臺(tái)計(jì)算機(jī)可以有若干通信端口,系統(tǒng)應(yīng)當(dāng)集中管理這些通信端口,以避免一個(gè)通信端口同時(shí)被兩個(gè)請(qǐng)求同時(shí)調(diào)用。
優(yōu)點(diǎn)
- 由于單例模式在內(nèi)存中只有一個(gè)實(shí)例,減少了內(nèi)存開銷。
- 單例模式可以避免對(duì)資源的多重占用,例如一個(gè)寫文件時(shí),由于只有一個(gè)實(shí)例存在內(nèi)存中,避免對(duì)同一個(gè)資源文件的同時(shí)寫操作。
- 單例模式可以再系統(tǒng)設(shè)置全局的訪問點(diǎn),優(yōu)化和共享資源訪問。由于單例模式在內(nèi)存中只有一個(gè)實(shí)例,減少了內(nèi)存開銷。
實(shí)現(xiàn)
網(wǎng)上盛行的單例模式的多種寫法,而事實(shí)上,對(duì)于個(gè)人來說,我們只需要熟記自己喜歡的寫法就好了,而那些非延遲加載的,非線程安全的,同步鎖導(dǎo)致效率低的,沒必要再說怎么寫了。但是序列化與反序列化的問題,由于是否要考慮該問題,所以有以下解決方案
1. 內(nèi)部類方式(我最愛的方式)
內(nèi)部類SingletonHolder只有在getInstance()方法第一次調(diào)用的時(shí)候才會(huì)被加載,實(shí)現(xiàn)了延遲加載,而且其加載過程是線程安全的,但是序列化反序列化問題沒有解決
public class Singleton {
private Singleton() { }
private static class SingletonHolder {
private final static Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
public void test(){
}
}
使用
Singleton.getInstance().test();
2.優(yōu)雅的枚舉方式
使用枚舉除了線程安全和防止反射強(qiáng)行調(diào)用構(gòu)造器之外,還提供了自動(dòng)序列化機(jī)制,防止反序列化的時(shí)候創(chuàng)建新的對(duì)象。因此,Effective Java推薦盡可能地使用枚舉來實(shí)現(xiàn)單列,但是在Android平臺(tái)上卻是不被推薦的
(PS:枚舉的原理并非想當(dāng)然的內(nèi)部靜態(tài)變量原理,[枚舉原理][1])
public enum Singleton {
INSTANCE;
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
Android中的應(yīng)用
如我們一開始說的,許多資源管理器設(shè)計(jì)成單例模式,那么我們的Android系統(tǒng)本身就有很多資源需要管理,最常見的是LayoutInflater 是單例模式,還有許多的manager,
(a) BluetoothOppManager
public class BluetoothOppManager {
private static final String TAG = "BluetoothOppManager";
private static final boolean V = Constants.VERBOSE;
// 創(chuàng)建private static類實(shí)例
private static BluetoothOppManager INSTANCE;
/** Used when obtaining a reference to the singleton instance. */
private static Object INSTANCE_LOCK = new Object();
...
/**
* Get singleton instance.
*/
public static BluetoothOppManager getInstance(Context context) {
synchronized (INSTANCE_LOCK) {
if (INSTANCE == null) {
INSTANCE = new BluetoothOppManager();
}
INSTANCE.init(context);
return INSTANCE;
}
}
(b). InputMethodManager
public final class InputMethodManager {
static final boolean DEBUG = false;
static final String TAG = "InputMethodManager";
static final Object mInstanceSync = new Object();
static InputMethodManager mInstance;
final IInputMethodManager mService;
final Looper mMainLooper;
/**
* Retrieve the global InputMethodManager instance, creating it if it
* doesn't already exist.
* @hide
*/
static public InputMethodManager getInstance(Context context) {
return getInstance(context.getMainLooper());
}
/**
* Internally, the input method manager can't be context-dependent, so
* we have this here for the places that need it.
* @hide
*/
static public InputMethodManager getInstance(Looper mainLooper) {
synchronized (mInstanceSync) {
if (mInstance != null) {
return mInstance;
}
IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
mInstance = new InputMethodManager(service, mainLooper);
}
return mInstance;
}
}
(c) 數(shù)不勝數(shù)
...
謝謝大家閱讀,如有幫助,來個(gè)喜歡或者關(guān)注吧!
本文作者:Anderson/Jerey_Jobs
簡(jiǎn)書地址:[Anderson大碼渣][2]
github地址:[Jerey_Jobs][3]
[2]: http://www.itdecent.cn/users/016a5ba708a0/
[3]: https://github.com/Jerey-Jobs