<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    kapok

    垃圾桶,嘿嘿,我藏的這么深你們還能找到啊,真牛!

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      455 隨筆 :: 0 文章 :: 76 評論 :: 0 Trackbacks
    http://www.uml.org.cn/j2ee/200501241.htm

    單例模式完全剖析(3)---- 探究簡單卻又使人迷惑的單例模式
    kevin 翻譯 選自:java研究組織
    使用注冊表

    使用一個單例類注冊表可以:
    • 在運行期指定單例類
    • 防止產生多個單例類子類的實例
      在例8的單例類中,保持了一個通過類名進行注冊的單例類注冊表:
      例8 帶注冊表的單例類
      1. import java.util.HashMap;
      2. import org.apache.log4j.Logger;
      3.  
      4. public class Singleton {
      5.    private static HashMap map = new HashMap();
      6.    private static Logger logger = Logger.getRootLogger();
      7.  
      8.    protected Singleton() {
      9.       // Exists only to thwart instantiation
      10.    }
      11.    public static synchronized Singleton getInstance(String classname) {
      12.       if(classname == nullthrow new IllegalArgumentException("Illegal classname");
      13.          Singleton singleton = (Singleton)map.get(classname);
      14.  
      15.       if(singleton != null) {
      16.          logger.info("got singleton from map: " + singleton);
      17.          return singleton;
      18.       }
      19.       if(classname.equals("SingeltonSubclass_One"))
      20.             singleton = new SingletonSubclass_One();         
      21.          else if(classname.equals("SingeltonSubclass_Two"))
      22.             singleton = new SingletonSubclass_Two();
      23.  
      24.       map.put(classname, singleton);
      25.       logger.info("created singleton: " + singleton);
      26.       return singleton;
      27.    }
      28.    // Assume functionality follows that's attractive to inherit
      29. }

      這段代碼的基類首先創建出子類的實例,然后把它們存儲在一個Map中。但是基類卻得付出很高的代價因為你必須為每一個子類替換它的getInstance()方法。幸運的是我們可以使用反射處理這個問題。

      使用反射


      在例9的帶注冊表的單例類中,使用反射來實例化一個特殊的類的對象。與例8相對的是通過這種實現,Singleton.getInstance()方法不需要在每個被實現的子類中重寫了。
      例9 使用反射實例化單例類
      1. import java.util.HashMap;
      2. import org.apache.log4j.Logger;
      3.  
      4. public class Singleton {
      5.    private static HashMap map = new HashMap();
      6.    private static Logger logger = Logger.getRootLogger();
      7.  
      8.    protected Singleton() {
      9.       // Exists only to thwart instantiation
      10.    }
      11.    public static synchronized Singleton getInstance(String classname) {
      12.       Singleton singleton = (Singleton)map.get(classname);
      13.  
      14.       if(singleton != null) {
      15.          logger.info("got singleton from map: " + singleton);
      16.          return singleton;
      17.       }
      18.       try {
      19.          singleton = (Singleton)Class.forName(classname).newInstance();
      20.       }
      21.       catch(ClassNotFoundException cnf) {
      22.          logger.fatal("Couldn't find class " + classname);    
      23.       }
      24.       catch(InstantiationException ie) {
      25.          logger.fatal("Couldn't instantiate an object of type " + classname);    
      26.       }
      27.       catch(IllegalAccessException ia) {
      28.          logger.fatal("Couldn't access class " + classname);    
      29.       }
      30.       map.put(classname, singleton);
      31.       logger.info("created singleton: " + singleton);
      32.  
      33.       return singleton;
      34.    }
      35. }


      關于單例類的注冊表應該說明的是:它們應該被封裝在它們自己的類中以便最大限度的進行復用。

      封裝注冊表


      例10列出了一個單例注冊表類。
      例10 一個SingletonRegistry類
      1. import java.util.HashMap;
      2. import org.apache.log4j.Logger;
      3.  
      4. public class SingletonRegistry {
      5.    public static SingletonRegistry REGISTRY = new SingletonRegistry();
      6.  
      7.    private static HashMap map = new HashMap();
      8.    private static Logger logger = Logger.getRootLogger();
      9.  
      10.    protected SingletonRegistry() {
      11.       // Exists to defeat instantiation
      12.    }
      13.    public static synchronized Object getInstance(String classname) {
      14.       Object singleton = map.get(classname);
      15.  
      16.       if(singleton != null) {
      17.          return singleton;
      18.       }
      19.       try {
      20.          singleton = Class.forName(classname).newInstance();
      21.          logger.info("created singleton: " + singleton);
      22.       }
      23.       catch(ClassNotFoundException cnf) {
      24.          logger.fatal("Couldn't find class " + classname);    
      25.       }
      26.       catch(InstantiationException ie) {
      27.          logger.fatal("Couldn't instantiate an object of type " + 
      28.                        classname);    
      29.       }
      30.       catch(IllegalAccessException ia) {
      31.          logger.fatal("Couldn't access class " + classname);    
      32.       }
      33.       map.put(classname, singleton);
      34.       return singleton;
      35.    }
      36. }

      注意我是把SingletonRegistry類作為一個單例模式實現的。我也通用化了這個注冊表以便它能存儲和取回任何類型的對象。例11顯示了的Singleton類使用了這個注冊表。
      例11 使用了一個封裝的注冊表的Singleton類
      1. import java.util.HashMap;
      2. import org.apache.log4j.Logger;
      3.  
      4. public class Singleton {
      5.  
      6.    protected Singleton() {
      7.       // Exists only to thwart instantiation.
      8.    }
      9.    public static Singleton getInstance() {
      10.       return (Singleton)SingletonRegistry.REGISTRY.getInstance(classname);
      11.    }
      12. }

      上面的Singleton類使用那個注冊表的唯一實例通過類名取得單例對象。
      現在我們已經知道如何實現線程安全的單例類和如何使用一個注冊表去在運行期指定單例類名,接著讓我們考查一下如何安排類載入器和處理序列化。

      Classloaders


      在許多情況下,使用多個類載入器是很普通的--包括servlet容器--所以不管你在實現你的單例類時是多么小心你都最終可以得到多個單例類的實例。如果你想要確保你的單例類只被同一個的類載入器裝入,那你就必須自己指定這個類載入器;例如:
      1. private static Class getClass(String classname) 
      2.                                          throws ClassNotFoundException {
      3.       ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
      4.  
      5.       if(classLoader == null)
      6.          classLoader = Singleton.class.getClassLoader();
      7.  
      8.       return (classLoader.loadClass(classname));
      9.    }
      10. }

      這個方法會嘗試把當前的線程與那個類載入器相關聯;如果classloader為null,這個方法會使用與裝入單例類基類的那個類載入器。這個方法可以用Class.forName()代替。

      序列化


      如果你序列化一個單例類,然后兩次重構它,那么你就會得到那個單例類的兩個實例,除非你實現readResolve()方法,像下面這樣:
      例12 一個可序列化的單例類
      1. import org.apache.log4j.Logger;
      2.  
      3. public class Singleton implements java.io.Serializable {
      4.    public static Singleton INSTANCE = new Singleton();
      5.  
      6.    protected Singleton() {
      7.       // Exists only to thwart instantiation.
      8.    }
      9. [b]      private Object readResolve() {
      10.             return INSTANCE;
      11.       }[/b]}

      上面的單例類實現從readResolve()方法中返回一個唯一的實例;這樣無論Singleton類何時被重構,它都只會返回那個相同的單例類實例。
      例13測試了例12的單例類:
      例13 測試一個可序列化的單例類
      1. import java.io.*;
      2. import org.apache.log4j.Logger;
      3. import junit.framework.Assert;
      4. import junit.framework.TestCase;
      5.  
      6. public class SingletonTest extends TestCase {
      7.    private Singleton sone = null, stwo = null;
      8.    private static Logger logger = Logger.getRootLogger();
      9.  
      10.    public SingletonTest(String name) {
      11.       super(name);
      12.    }
      13.    public void setUp() {
      14.       sone = Singleton.INSTANCE;
      15.       stwo = Singleton.INSTANCE;
      16.    }
      17.    public void testSerialize() {
      18.       logger.info("testing singleton serialization...");
      19. [b]      writeSingleton();
      20.       Singleton s1 = readSingleton();
      21.       Singleton s2 = readSingleton();
      22.       Assert.assertEquals(true, s1 == s2);[/b]   }
      23.    private void writeSingleton() {
      24.       try {
      25.          FileOutputStream fos = new FileOutputStream("serializedSingleton");
      26.          ObjectOutputStream oos = new ObjectOutputStream(fos);
      27.          Singleton s = Singleton.INSTANCE;
      28.  
      29.          oos.writeObject(Singleton.INSTANCE);
      30.          oos.flush();
      31.       }
      32.       catch(NotSerializableException se) {
      33.          logger.fatal("Not Serializable Exception: " + se.getMessage());
      34.       }
      35.       catch(IOException iox) {
      36.          logger.fatal("IO Exception: " + iox.getMessage());
      37.       }
      38.    }
      39.    private Singleton readSingleton() {
      40.       Singleton s = null;
      41.  
      42.       try {
      43.          FileInputStream fis = new FileInputStream("serializedSingleton");
      44.          ObjectInputStream ois = new ObjectInputStream(fis);
      45.          s = (Singleton)ois.readObject();
      46.       }
      47.       catch(ClassNotFoundException cnf) {
      48.          logger.fatal("Class Not Found Exception: " + cnf.getMessage());
      49.       }
      50.       catch(NotSerializableException se) {
      51.          logger.fatal("Not Serializable Exception: " + se.getMessage());
      52.       }
      53.       catch(IOException iox) {
      54.          logger.fatal("IO Exception: " + iox.getMessage());
      55.       }
      56.       return s;
      57.    }
      58.    public void testUnique() {
      59.       logger.info("testing singleton uniqueness...");
      60.       Singleton another = new Singleton();
      61.  
      62.       logger.info("checking singletons for equality");
      63.       Assert.assertEquals(true, sone == stwo);
      64.    }
      65. }

      前面這個測試案例序列化例12中的單例類,并且兩次重構它。然后這個測試案例檢查看是否被重構的單例類實例是同一個對象。下面是測試案例的輸出:
      1.  
      2. Buildfile: build.xml
      3.  
      4. init:
      5.      [echo] Build 20030422 (22-04-2003 11:32)
      6.  
      7. compile:
      8.  
      9. run-test-text:
      10.      [java] .INFO main: testing singleton serialization...
      11.      [java] .INFO main: testing singleton uniqueness...
      12.      [java] INFO main: checking singletons for equality
      13.  
      14.      [java] Time: 0.1
      15.  
      16.      [java] OK (2 tests)

      單例模式結束語


      單例模式簡單卻容易讓人迷惑,特別是對于Java的開發者來說。在這篇文章中,作者演示了Java開發者在顧及多線程、類載入器和序列化情況如何實現單例模式。作者也展示了你怎樣才能實現一個單例類的注冊表,以便能夠在運行期指定單例類。
    posted on 2005-04-18 14:33 笨笨 閱讀(332) 評論(0)  編輯  收藏 所屬分類: J2EEALLJ2SE
    主站蜘蛛池模板: eeuss影院免费92242部| 18禁在线无遮挡免费观看网站| 亚洲日本va一区二区三区| 污视频网站在线免费看| 1000部拍拍拍18勿入免费视频下载| 我要看免费的毛片| 国产A在亚洲线播放| 风间由美在线亚洲一区| 最近免费中文在线视频| 亚洲毛片在线免费观看| baoyu122.永久免费视频| 美女黄网站人色视频免费国产| 香蕉视频在线观看亚洲| 一个人看的免费观看日本视频www 一个人看的免费视频www在线高清动漫 | 色天使亚洲综合在线观看| 成人免费乱码大片A毛片| 在线观看人成网站深夜免费| 久久青青草原亚洲AV无码麻豆| 日本在线观看免费高清| 中文字幕中韩乱码亚洲大片| 猫咪免费人成在线网站 | 最近免费最新高清中文字幕韩国| 亚洲无码视频在线| 久久久久久久久无码精品亚洲日韩| 国产免费一区二区三区VR| 久久精品国产亚洲αv忘忧草| 免费人妻无码不卡中文字幕系 | 99久久99热精品免费观看国产| 亚洲福利电影在线观看| 日韩免费一区二区三区| 亚洲日本久久一区二区va| 最近中文字幕无免费| 亚洲日韩中文字幕无码一区| 亚洲国产专区一区| 免费无码国产在线观国内自拍中文字幕| 国产91精品一区二区麻豆亚洲| 毛片无码免费无码播放| 亚洲国产高清国产拍精品| 啦啦啦高清视频在线观看免费| 亚洲国产精品综合久久网各| 曰曰鲁夜夜免费播放视频|