模式的定義:
確保某一個類只有一個實例,而且自行實例化並向整個系統提供這個實例。
使用場景
確保某個類有且只有一個對象的場景。
UML類圖
簡單示例:
單例模式是設計模式中最簡單的,只有一個單例類,沒有其他的層次結構與抽象。該模式需要確保該類只能生成一個對象,通常是該類需要消耗太多的資源或者沒有沒有多個實例的理由。例如一個公司只有一個CEO、一臺電腦通常只有一個顯示器等。下面我們以公司裏的CEO爲例來簡單演示一下,一個公司可以有幾個VP,無數個員工,但是CEO只有一個,請看下面的實現代理 :
package com.dp.example.singleton;
/**
* 人的基類
* @author mrsimple
*
*/
public abstract class Person {
public abstract void talk() ;
}
// 普通員工
public class Staff extends Person {
@Override
public void talk() {
}
}
// 副總裁
public class VP extends Person {
@Override
public void talk() {
}
}
// CEO, 單例模式
public class CEO extends Person {
private static final CEO mCeo = new CEO();
private CEO() {
}
public static CEO getCeo() {
return mCeo;
}
@Override
public void talk() {
System.out.println("CEO發表講話");
}
}
// 公司類
import java.util.ArrayList;
import java.util.List;
public class Company {
private List allPersons = new ArrayList();
public void addStaff(Person per) {
allPersons.add(per);
}
public void showAllStaffs() {
for (Person per : allPersons) {
System.out.println("Obj : " + per.toString());
}
}
}
// test
public class Test {
public static void main(String[] args) {
Company cp = new Company() ;
Person ceo1 = CEO.getCeo() ;
Person ceo2 = CEO.getCeo() ;
cp.addStaff(ceo1);
cp.addStaff(ceo2);
Person vp1 = new VP() ;
Person vp2 = new VP() ;
Person staff1 = new Staff() ;
Person staff2 = new Staff() ;
Person staff3 = new Staff() ;
cp.addStaff(vp1);
cp.addStaff(vp2);
cp.addStaff(staff1);
cp.addStaff(staff2);
cp.addStaff(staff3);
cp.showAllStaffs();
}
}
單列模式的幾種實現方法:
package com.dp.example.singleton;
public class Singleton {
private static Singleton mInstance = null;
private Singleton() {
}
public void doSomething() {
System.out.println("do sth.");
}
/**
* 方式二、double-check, 避免併發時創建了多個實例, 該方式不能完全避免併發帶來的破壞.
*
* @return
*/
public static Singleton getInstance() {
if (mInstance == null) {
synchronized (Singleton.class) {
if (mInstance == null) {
mInstance = new Singleton();
}
}
}
return mInstance;
}
/**
* 方式三 : 在第一次加載SingletonHolder時初始化一次mOnlyInstance對象, 保證唯一性, 也延遲了單例的實例化,
* 如果該單例比較耗資源可以使用這種模式.
*
* @return
*/
public static Singleton getInstanceFromHolder() {
return SingletonHolder.mOnlyInstance;
}
/**
* 靜態內部類
*
* @author mrsimple
*
*/
private static class SingletonHolder {
private static final Singleton mOnlyInstance = new Singleton();
}
/**
* 方式四 : 枚舉單例, 線程安全
* @author mrsimple
*
*/
enum SingletonEnum {
INSTANCE;
public void doSomething() {
System.out.println("do sth.");
}
}
/**
* 方式五 : 註冊到容器, 根據key獲取對象.一般都會有多種相同屬性類型的對象會註冊到一個map中
* instance容器
*/
private static Map<string singleton=""> objMap = new HashMap<string singleton="">();
/**
* 註冊對象到map中
* @param key
* @param instance
*/
public static void registerService(String key, Singleton instance) {
if (!objMap.containsKey(key) ) {
objMap.put(key, instance) ;
}
}
/**
* 根據key獲取對象
* @param key
* @return
*/
public static Singleton getService(String key) {
return objMap.get(key) ;
}
}
優點與缺點
優點 :
1、由於單例模式在內存中只有一個實例,減少了內存開支,特別是一個對象需要頻繁地創建、銷燬時,而且創建或銷燬時性能又無法優化,單例模式的優勢就非常明顯。
2、由於單例模式只生成一個實例,所以減少了系統的性能開銷,當一個對象的產生需要比較多的資源時,如讀取配置、產生其他依賴對象時,則可以通過在應用啓動時直接產生一個單例對象,然後用永久駐留內存的方式來解決;
3、單例模式可以避免對資源的多重佔用,例如一個寫文件動作,由於只有一個實例存在內存中,避免對同一個資源文件的同時寫操作。
4、單例模式可以在系統設置全局的訪問點,優化和共享資源訪問,例如可以設計一個單例類,負責所有數據表的映射處理。
缺點 :
1、單例模式一般沒有接口,擴展很困難,若要擴展,除了修改代碼基本上沒有第二種途徑可以實現。
2、單例模式與單一職責原則有衝突。