設計模式 – 單例模式(Singleton)

ü  核心:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點;

ü  用途:想保證某個特定類的對象實例絕對只有1個的情況;

ü  結構圖:

ü  方法:可以把類的屬性定義爲static字段,再以Singleton類的對象實例進行初始化,而這個初始化的操作僅僅在加載Singleton類時進行一次,Singleton類的構造函數是private(所有類都有構造方法,不編碼則系統默認生成空的構造方法,若有顯示定義的構造方法,默認的構造方法就會失效,因此寫成private,外部程序就不能用new來實例化該類了),主要是爲了禁止從非Singleton類調用構造函數new出新的實例,而向要取得Singleton類的惟一對象實例的方法就是getInstance

ü  單例模式和實用類的區別:實用類通常也會採用私有化的構造方法來避免其有實例,但是實用類不保存狀態,僅提供一些靜態方法或者靜態屬性讓你使用,而單例類是有狀態的,實用類不能用於繼承多態,而單例雖然實例唯一,卻是可以有子類來繼承的,實用類只不過是一些方法屬性的集合,而單例卻是有這唯一的對象實例。

ü  還需要注意,在多線程的程序中,多個線程同時訪問Singleton類,調用getInstance方法,會有可能造成創建多個實例。這個時候可以利用JAVA裏的線程同步機制,爲getInstance方法添加synchronized關鍵字(但不能對單例的實例化對象instance添加鎖,因爲該對象可能尚未實例化),而避免每次加鎖影響性能,可以使用雙重鎖定”(Double-Check Locking)

    說明:仔細觀察,我們不難發現,上述程序中有兩個地方需要判斷instance是否爲空,這主要是因爲:當instancenull並且同時有兩個線程調用GetInstance()方法時,它們都將可以通過第一重instance == null的判斷,然後由於lock機制,這兩個線程則只有一個可以進入,另一個在外排隊等候,必須要其中的一個進入並出來後,另一個才能進入,而不要誤以爲只能執行其中一個,因此沒有第二重的Instance是否爲空的判斷,則兩個線程都會同時創建出實例,沒有達到單例的目的。

實例一:

Ø  單例類 -- 文件Singleton.java

package com.yilong.designpattern.singleton;

public class Singleton {

    private static Singleton singleton = new Singleton();

    private int ticketId = 1000;

    private Singleton() {

       System.out.println("已產生對象實例");

    }

    public static Singleton getInstance() {

       return singleton;

    }

    public int getNextTicketId() {

       return ticketId ++;

    }

}

Ø  測試類 文件Main.java

package com.yilong.designpattern.singleton;

public class Main {

    public static void main(String[] args) {

       System.out.println("Start");

       Singleton singleton1 = Singleton.getInstance();

       Singleton singleton2 = Singleton.getInstance();

       System.out.println(singleton1 == singleton2);

       System.out.println(singleton1);

       System.out.println(singleton2);

       System.out.println(singleton1.getNextTicketId());

       System.out.println(singleton2.getNextTicketId());

       System.out.println("End");

    }

}

打印結果:

Start

已產生對象實例

true

com.yilong.designpattern.singleton.Singleton@c17164

com.yilong.designpattern.singleton.Singleton@c17164

1000

1001

End

實例二:通過判斷對象實例是否爲空的方法實例化,但是這種方法在多線程的結構下可能達不到預期的效果,所以最好在方法前添加關鍵字synchronized

Ø  單例類 文件Singleton1.java

package com.yilong.designpattern.test;

public class Singleton1 {

    private static Singleton1 testSingleton = null;

    private Singleton1() {

       System.out.println("初始化!");

    }

    public static synchronized Singleton1 getInstance() {

       if(testSingleton == null) {//儘管加入了鎖,但這個判斷還是必須的

           testSingleton = new Singleton1();

       }

       return testSingleton;

    }

}

實例三:實例數目有限個的情況。

Ø  文件Singleton2.java

package com.yilong.designpattern.test;

public class Singleton2 {

    public static final int SIZE = 3;

    private int id;

    private static Singleton2[] singletons =

           {new Singleton2(0), new Singleton2(1), new Singleton2(2)};

    private Singleton2(int id) {

       System.out.println("初始化!");

       this.id = id;

    }

    public static synchronized Singleton2 getInstance(int id) {

       if(id>=0 && id<=3) {

           return singletons[id];

       } else {

           return null;

       }

    }

}

Ø  測試類 文件Test2.java

package com.yilong.designpattern.test;

public class Test1 {

    public static void main(String[] args) {

       System.out.println("Start");

       Singleton2 singleton1 = Singleton2.getInstance(0);

       Singleton2 singleton2 = Singleton2.getInstance(1);

       Singleton2 singleton3 = Singleton2.getInstance(2);

       Singleton2 singleton4 = Singleton2.getInstance(0);

       System.out.println(singleton1);

       System.out.println(singleton2);

       System.out.println(singleton3);

       System.out.println(singleton1 == singleton4);

       System.out.println("End");

    }

}

打印結果:

Start

初始化!

初始化!

初始化!

com.yilong.designpattern.test.Singleton2@c17164

com.yilong.designpattern.test.Singleton2@1fb8ee3

com.yilong.designpattern.test.Singleton2@61de33

true

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