1. 程式人生 > 實用技巧 >模擬排球比賽

模擬排球比賽

單例模式

GoF定義:保證一個類只有一個物件,並且提供一個全域性的訪問點

概念

一個特別的類只有一個例項,無論什麼時候使用都是這同一個例項

例子

現實生活:假設有兩個板球隊伍在比賽,賽前兩隊的隊長要投幣決定哪方先擊球,此時每個隊的隊長只能有一個,如果原來沒有,那麼要新選出一個隊長
程式碼世界:程式碼只在一個檔案系統上操作,那麼這個檔案系統的物件應該是全域性唯一的

展示

  1. 將構造器宣告為private
  2. 當建立這個類的例項時,如果已經存在,則使用這個例項,否則新建一個例項

public class SingletonPattern {

    public static void main(String[] args) {
        System.out.println("***Singleton Pattern Demo***\n");
        System.out.println("Trying to make a captain for our team");
        MakeACaptain c1 = MakeACaptain.getCaptain();
        System.out.println("Trying to make another captain for our team");
        MakeACaptain c2 = MakeACaptain.getCaptain();
        if (c1 == c2)
        {
            System.out.println("c1 and c2 are same instance");
        }
    }
}

class MakeACaptain {

    private static MakeACaptain makeACaptain;

    private MakeACaptain() {}

    public static MakeACaptain getCaptain() {
        if (makeACaptain == null) {
            makeACaptain = new MakeACaptain();
            System.out.println("New Captain selected for our team");
        } else {
            System.out.print("You already have a Captain for your team.");
            System.out.println("Send him for the toss.");
        }
        return makeACaptain;
    }
}

附加資訊

上面程式碼的初始化模式為lazy initialization。因為直到靜態方法被呼叫這個物件都不存在(可以在靜態變數預設值直接新建一個物件)

上面程式碼的例項建立方式是執行緒不安全的,即(判斷物件是否為空可能會讓兩個執行緒進入,那麼會建立兩個物件,那麼它們持有的就不是同一個物件)

改進方式:

  1. 將返回例項的方法設為synchronized(同步操作會有額外開銷(鎖的開銷))
public static synchronized MakeACaptain getCaptain()
  1. 提前把例項建立好
class MakeACaptain {

    private static MakeACaptain makeACaptain = new MakeACaptain();

    private MakeACaptain() {}

    public static synchronized MakeACaptain getCaptain() {
        return makeACaptain
    }
}
  1. 不使用同步,也不使用提前初始化,Java中標準的單例實現(這個方法的牛逼之處在於,類在載入時會有靜態變數初始化的過程,這種方法利用了內部類的靜態成員變數初始化需要載入內部類,實現了lazy initialization。對於final變數,只有當構造器呼叫完成,其它的執行緒才能看到,這個(Java語言的)機制保證了執行緒安全
class MakeACaptain
{
      private static MakeACaptain _captain;
      private MakeACaptain() { }
      //Bill Pugh solution
      private static class SingletonHelper{
            //Nested class is referenced after getCaptain() is called
            private static final MakeACaptain _captain = new MakeACaptain();
      }
      public static MakeACaptain getCaptain()
      {
            return SingletonHelper._captain;
      }
}