Java23種設計模式案例:單例模式(Singleton)

單例對象(Singleton)是一種經常使用的設計模式。在Java應用中,單例對象能保證在一個JVM中,該對象只有一個實例存在。java

一、適用場景

須要使得類的一個對象成爲系統運行過程當中的惟一實例。設計模式

二、優勢

    1)實例控制多線程

單例模式會阻止其餘對象實例化其本身的單例對象的副本,從而確保全部對象都訪問惟一實例。spa

     2)靈活性線程

由於類控制了實例化過程,因此類能夠靈活更改實例化過程。設計

 

三、缺點

    1)開銷code

雖然數量不多,但若是每次對象請求引用時都要檢查是否存在類的實例,將仍然須要一些開銷。能夠經過使用靜態初始化解決此問題。對象

    2)可能的開發混淆內存

使用單例對象(尤爲在類庫中定義的對象)時,開發人員必須記住本身不能使用new關鍵字實例化對象。由於可能沒法訪問庫源代碼,所以應用程序開發人員可能會意外發現本身沒法直接實例化此類。開發

    3)對象生存期

不能解決刪除單個對象的問題。在提供內存管理的語言中(例如基於.NET Framework的語言),只有單例類可以致使實例被取消分配,由於它包含對該實例的私有引用。在某些語言中(如 C++),其餘類能夠刪除對象實例,但這樣會致使單例類中出現懸浮引用。

四、代碼示例

    1)關係圖

    2)代碼實現

        實現方式1:惡漢模式

//沒有達到lazy loading的效果
class HungrySingleton{
    private static HungrySingleton singleton=new HungrySingleton();
    private HungrySingleton(){}
    public static HungrySingleton getInstance(){
        return singleton;
    }
}

        實現方式2:懶漢模式

class LazySingleton{
    private static LazySingleton singleton;
    private LazySingleton(){
    }
    public static LazySingleton getInstance(){
        if(singleton==null){
            singleton=new LazySingleton();
        }
        return singleton;
    }  
}

        實現方式3:靜態內部類

//加載時不會初始化靜態變量INSTANCE,由於沒有主動使用,達到Lazy loading
class InternalSingleton{
    private static class SingletonHolder{
        private final static  InternalSingleton INSTANCE=new InternalSingleton();
    }  
    private InternalSingleton(){}
    public static InternalSingleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

        實現方式4:使用枚舉

//《Effective Java》做者推薦使用的方法,優勢:不只能避免多線程同步問題,並且還能防止反序列化從新建立新的對象
enum EnumSingleton{
    INSTANCE;
    public void doSomeThing(){
    }
}

        實現方式5:雙重校驗鎖

//帶有雙重校驗鎖的單例模式
class LockSingleton{
    private volatile static LockSingleton singleton;
    private LockSingleton(){}
     
    public static LockSingleton getInstance(){
        if(singleton==null){
            synchronized(LockSingleton.class){
                if(singleton==null){
                    singleton=new LockSingleton();
                }
            }
        }
        return singleton;
    }   
}

        實現方式6:登記式單例

//相似Spring裏面的方法,將類名註冊,下次從裏面直接獲取。
class Singleton3 {
    private static Map<String,Singleton3> map = new HashMap<String,Singleton3>();
    static{
        Singleton3 single = new Singleton3();
        map.put(single.getClass().getName(), single);
    }
    //保護的默認構造子
    protected Singleton3(){}
    //靜態工廠方法,返還此類唯一的實例
    public static Singleton3 getInstance(String name) {
        if(name == null) {
            name = Singleton3.class.getName();
            System.out.println("name == null"+"--->name="+name);
        }
        if(map.get(name) == null) {
            try {
                map.put(name, (Singleton3) Class.forName(name).newInstance());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return map.get(name);
    }
    //一個示意性的商業方法
    public String about() {    
        return "Hello, I am RegSingleton.";    
    }    
    public static void main(String[] args) {
        Singleton3 single3 = Singleton3.getInstance(null);
        System.out.println(single3.about());
    }
}
相關文章
相關標籤/搜索