單例模式
1 定義
Ensure a class has only one instance, and provide a global point of access to it.(確保某一個類只有一個實例,而且自行實例化并向整個系統提供這個實例。)
single.png
2 單例通用代碼
public class Singleton {
private static final Singleton singleton = new Singleton();
/**
* 構造函數設為私有,以防外部調用。
*/
private Singleton(){
}
/**
* 暴露外部訪問方法
* @return
*/
public static Singleton getInstance(){
return singleton;
}
}
3 使用場景
在項目一個類要求只能有一個對象的時候,或者避免產生多個對象去訪問資源。
4 單例的優點
- 單例在內存中只有一個實例,減少內存開銷。
- 單例只生成一個實例,減少系統性能開銷,比如讀取文件之類的通過單例產生后常住內存中。
- 單例可以避免統一資源的多重占用,比如讀寫文件。
- 單例可以在系統設置全局訪問點,優化和共享資源訪問。
5 單例的缺點
- 單例沒有接口,擴展困難。
- 單例與單一職責有沖突。這個看具體情況。
6 單例類型
Double Check Lock (DCL)
public class DoubleSingleton {
private static DoubleSingleton mInstance;
private DoubleSingleton(){}
public static DoubleSingleton getInstance(){
//第一次判空,當不為空的時候直接返回,避免觸發同步鎖.
if(mInstance == null){
synchronized (DoubleSingleton.class){
//第二次判空,為空的時候創建mInstance對象
if(mInstance == null){
mInstance = new DoubleSingleton();
}
}
}
return mInstance;
}
}
靜態內部類單例模式
public class StaticInnerSingleton {
private StaticInnerSingleton(){}
public static StaticInnerSingleton getInstance(){
return SingletonHolder.INSTANCE;
}
/**
* 靜態內部類,內部有一個靜態變量INSTANCE
*/
private static class SingletonHolder{
private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton();
}
}
靜態內部類單例模式,當StaticInnerSingleton初始化的時候不會創建,而當調用getInstance的時候才會創建SingletonHolder靜態內部類,才在內存初始化對象。
枚舉單例類型
public enum EnumSingleton {
INSTANCE;
public String getStr(){
return "123";
}
}
使用容器實現單例
public class SingletonManager {
private static Map<String,Object> singletorManager = new HashMap<String,Object>();
private SingletonManager(){}
public static void regisetService(String key,Object instance){
if(!singletorManager.containsKey(key)){
singletorManager.put(key,instance);
}
}
public static Object getService(String key){
return singletorManager.get(key);
}
}
public class SingletonManagerTest {
@Before
public void setUp() throws Exception {
SingletonManager.regisetService("DoubleSingleton",DoubleSingleton.getInstance());
SingletonManager.regisetService("EnumSingleton",EnumSingleton.INSTANCE);
SingletonManager.regisetService("StaticInnerSingleton",StaticInnerSingleton.getInstance());
}
@Test
public void getService() throws Exception {
assertNotNull(SingletonManager.getService("DoubleSingleton"));
}
}