閱讀769 返回首頁    go 技術社區[雲棲]


Design Pattern: Registry of Singleton 模式

  學習是分享和合作式的!

轉載請注明出處:https://blog.csdn.net/wdzxl198/article/details/9248821; 

文章摘自: https://www.riabook.cn/doc/designpattern/; 

考慮使用 Singleton 模式 時擁有子類別的問題,在Singleton模式中的getInstance()通常是一個靜態方法,不能在子類別中重新定義它,關於子類別實例的產生交由getInstance()來進行是最好的選擇,例如:

   1: public class Singleton {
   2:      private static Singleton instance = null;
   3:      private Singleton() 
   4:     {
   5:          // ....
   6:  
   7:     }
   8:      public static Singleton getInstance() 
   9:     {
  10:         if (instance == null) 
  11:         {
  12:      // 
  13:             getEnv表示係統環境變數
  14:              
  15:             String style = getEnv("style");
  16:              
  17:             if (style.equals("child1")) 
  18:                 instance = new ChildSingleton1(); 
  19:             else if(style.equals("child2r"))
  20:                 instance = new ChildSingleton2();
  21:              else
  22:                 instance = new Singleton();
  23:            }
  24:            return _instance;
  25:      }
  26:      // ....
  27: }

上麵這個程式片段改寫自 Gof 書中關於Singleton的例子,並用Java實現;在書中指出,這個例子的缺點是每增加一個子類別,getInstance()就必須重新修改,這個問題在Java中可以使用Reflection機製來解決:

   1: public class Singleton {
   2:     private static Singleton instance = null;
   3:     private Singleton() {
   4:         // ....
   5:     }
   6:     public static Singleton getInstance() {
   7:         if (instance == null) {
   8:             // getEnv表示環境變數
   9:             String style = getEnv("style");
  10:             try {
  11:                 instance = (Singleton)
  12:                           Class.forName(style).newInstance();
  13:             }
  14:             catch(Exception e) {
  15:                 System.out.println(
  16:                    "Sorry! No such class defined!");
  17:             }
  18:         }
  19:         return instance;
  20:     }
  21:     // ....
  22: }

上麵的方式使用了Java的Reflection機製,並透過環境變數設定要產生的子類Singleton,如果不使用Reflection的話,Gof 書中提出的改進方法是使用Registry of Singleton方法:

   1: import java.util.*;
   2: public class Singleton {
   3:     // 注冊表,用於注冊子類別物件
   4:     private static Map registry = new HashMap();
   5:     private static Singleton instance;
   6:     public static void register(
   7:                  String name, Singleton singleton) {
   8:         registry.put(name, singleton);
   9:     }
  10:     public static Singleton getInstance() {
  11:         if (instance == null) {
  12:             // getEnv表示取得環境變數
  13:             String style = getEnv("style");
  14:             instance = lookup(style);
  15:         }
  16:         return instance;
  17:     }
  18:     protected static Singleton lookup(String name) {
  19:         return (Singleton) registry.get(name);
  20:     }
  21: }

在Gof書中使用List來實現注冊表,而在這邊使用HasMap類別來實現,它是由Java SE所提供的;在父類別中提供一個register() 以注冊Singleton的子類別所產生之實例,而注冊的時機可以放在子類別的建構方法中加以實現,例如:

   1: public class ChildSingleton1 extends Singleton {
   2:     public ChildSingleton1() {
   3:         // ....
   4:         // 注冊子類別物件
   5:         register(getClass().getName(), this); 
   6:     }
   7: }

若要利用Singleton,則先使用這個子類別產生物件,這會向父類別注冊物件,之後透過Singleton父類別來取得物件:

   1: // 必須先啟始這段注冊程序
   2: // 產生並注冊ChildSingleton1物件
   3: new ChildSingleton1();
   4: // 產生並注冊ChildSingleton2物件
   5: new ChildSingleton2();
   6:  
   7: // 注冊完成,可以使用父類別來取得子類的Singleton
   8: // 至於取回何哪一個,視您的環境變數設置決定
   9: Singleton childSingleton = Singleton.getInstance();
  10:  
這種方式的缺點是您必須在程式中啟始一段程序,先向父類別注冊子類的Singleton,之後才能透過父類別來取得指定的子類別Singleton實例, 好處是可以適用於沒有Reflection機製的語言,如果您想要改變Singleton父類傳回的子類Singleton,可以在上麵的 Singleton類別中加入一個reset()方法,將instance設定為null,然後重新設定環境變數,之後再利用 Singleton父類的getInstance()方法重新取得注冊表中的其它子類。
事實上Registry of Singleton的真正優點正在於此,您可以使用父類別來統一管理多個繼承的子類別之Singleton實例,您可以在需要的時候再向父類別注冊子類 Singleton,必要時隨時調整傳回的子類別Singleton。

Edit by Atlas

Time 2013/7/5 09:31

最後更新:2017-04-03 16:48:30

  上一篇:go NHibernate - ICriteria 查詢
  下一篇:go Design Pattern: Builder 模式