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

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

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

    kapok

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

      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      455 隨筆 :: 0 文章 :: 76 評(píng)論 :: 0 Trackbacks
    http://www.uml.org.cn/j2ee/j2ee122401.htm

    Java模式設(shè)計(jì)之單例模式(一)
    閻宏 作者授權(quán)

      作為對(duì)象的創(chuàng)建模式[GOF95], 單例模式確保某一個(gè)類(lèi)只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。這個(gè)類(lèi)稱(chēng)為單例類(lèi)。

      注:本文乃閻宏博士的《Java與模式》一書(shū)的第十五章。

      引言

      單例模式的要點(diǎn)

      單例單例

      顯然單例模式的要點(diǎn)有三個(gè);一是某各類(lèi)只能有一個(gè)實(shí)例;二是它必須自行創(chuàng)建這個(gè)事例;三是它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。在下面的對(duì)象圖中,有一個(gè)"單例對(duì)象",而"客戶(hù)甲"、"客戶(hù)乙" 和"客戶(hù)丙"是單例對(duì)象的三個(gè)客戶(hù)對(duì)象。可以看到,所有的客戶(hù)對(duì)象共享一個(gè)單例對(duì)象。而且從單例對(duì)象到自身的連接線(xiàn)可以看出,單例對(duì)象持有對(duì)自己的引用。



      資源管理

      一些資源管理器常常設(shè)計(jì)成單例模式。

      在計(jì)算機(jī)系統(tǒng)中,需要管理的資源包括軟件外部資源,譬如每臺(tái)計(jì)算機(jī)可以有若干個(gè)打印機(jī),但只能有一個(gè)Printer Spooler, 以避免兩個(gè)打印作業(yè)同時(shí)輸出到打印機(jī)中。每臺(tái)計(jì)算機(jī)可以有若干傳真卡,但是只應(yīng)該有一個(gè)軟件負(fù)責(zé)管理傳真卡,以避免出現(xiàn)兩份傳真作業(yè)同時(shí)傳到傳真卡中的情況。每臺(tái)計(jì)算機(jī)可以有若干通信端口,系統(tǒng)應(yīng)當(dāng)集中管理這些通信端口,以避免一個(gè)通信端口同時(shí)被兩個(gè)請(qǐng)求同時(shí)調(diào)用。

      需要管理的資源包括軟件內(nèi)部資源,譬如,大多數(shù)的軟件都有一個(gè)(甚至多個(gè))屬性(properties)文件存放系統(tǒng)配置。這樣的系統(tǒng)應(yīng)當(dāng)由一個(gè)對(duì)象來(lái)管理一個(gè)屬性文件。

      需要管理的軟件內(nèi)部資源也包括譬如負(fù)責(zé)記錄網(wǎng)站來(lái)訪(fǎng)人數(shù)的部件,記錄軟件系統(tǒng)內(nèi)部事件、出錯(cuò)信息的部件,或是對(duì)系統(tǒng)的表現(xiàn)進(jìn)行檢查的部件等。這些部件都必須集中管理,不可政出多頭。

      這些資源管理器構(gòu)件必須只有一個(gè)實(shí)例,這是其一;它們必須自行初始化,這是其二;允許整個(gè)系統(tǒng)訪(fǎng)問(wèn)自己這是其三。因此,它們都滿(mǎn)足單例模式的條件,是單例模式的應(yīng)用。

      一個(gè)例子:Windows 回收站

      Windows 9x 以后的視窗系統(tǒng)中都有一個(gè)回收站,下圖就顯示了Windows 2000 的回收站。



      在整個(gè)視窗系統(tǒng)中,回收站只能有一個(gè)實(shí)例,整個(gè)系統(tǒng)都使用這個(gè)惟一的實(shí)例,而且回收站自行提供自己的實(shí)例。因此,回收站是單例模式的應(yīng)用。

      雙重檢查成例

      在本章最后的附錄里研究了雙重檢查成例。雙重檢查成例與單例模式并無(wú)直接的關(guān)系,但是由于很多C 語(yǔ)言設(shè)計(jì)師在單例模式里面使用雙重檢查成例,所以這一做法也被很多Java 設(shè)計(jì)師所模仿。因此,本書(shū)在附錄里提醒讀者,雙重檢查成例在Java 語(yǔ)言里并不能成立,詳情請(qǐng)見(jiàn)本章的附錄。

    單例模式的結(jié)構(gòu)

      單例模式有以下的特點(diǎn):

       .. 單例類(lèi)只可有一個(gè)實(shí)例。

       .. 單例類(lèi)必須自己創(chuàng)建自己這惟一的實(shí)例。

       .. 單例類(lèi)必須給所有其他對(duì)象提供這一實(shí)例。

      雖然單例模式中的單例類(lèi)被限定只能有一個(gè)實(shí)例,但是單例模式和單例類(lèi)可以很容易被推廣到任意且有限多個(gè)實(shí)例的情況,這時(shí)候稱(chēng)它為多例模式(Multiton Pattern) 和多例類(lèi)(Multiton Class),請(qǐng)見(jiàn)"專(zhuān)題:多例(Multiton )模式與多語(yǔ)言支持"一章。單例類(lèi)的簡(jiǎn)略類(lèi)圖如下所示。



      由于Java 語(yǔ)言的特點(diǎn),使得單例模式在Java 語(yǔ)言的實(shí)現(xiàn)上有自己的特點(diǎn)。這些特點(diǎn)主要表現(xiàn)在單例類(lèi)如何將自己實(shí)例化上。

      餓漢式單例類(lèi)餓漢式單例類(lèi)是在Java 語(yǔ)言里實(shí)現(xiàn)得最為簡(jiǎn)便的單例類(lèi),下面所示的類(lèi)圖描述了一個(gè)餓漢式單例類(lèi)的典型實(shí)現(xiàn)。



      從圖中可以看出,此類(lèi)已經(jīng)自已將自己實(shí)例化。

      代碼清單1:餓漢式單例類(lèi)

    public class EagerSingleton 

    private static final EagerSingleton m_instance = 
    new EagerSingleton(); 
    /** 
    * 私有的默認(rèn)構(gòu)造子 
    */ 
    private EagerSingleton() { } 
    /** 
    * 靜態(tài)工廠(chǎng)方法 
    */ 
    public static EagerSingleton getInstance() 
    {

    ·224·Java 與模式 
    return m_instance; 
    }


      讀者可以看出,在這個(gè)類(lèi)被加載時(shí),靜態(tài)變量m_instance 會(huì)被初始化,此時(shí)類(lèi)的私有構(gòu)造子會(huì)被調(diào)用。這時(shí)候,單例類(lèi)的惟一實(shí)例就被創(chuàng)建出來(lái)了。

      Java 語(yǔ)言中單例類(lèi)的一個(gè)最重要的特點(diǎn)是類(lèi)的構(gòu)造子是私有的,從而避免外界利用構(gòu)造子直接創(chuàng)建出任意多的實(shí)例。值得指出的是,由于構(gòu)造子是私有的,因此,此類(lèi)不能被繼承。

      懶漢式單例類(lèi)

      與餓漢式單例類(lèi)相同之處是,類(lèi)的構(gòu)造子是私有的。與餓漢式單例類(lèi)不同的是,懶漢式單例類(lèi)在第一次被引用時(shí)將自己實(shí)例化。如果加載器是靜態(tài)的,那么在懶漢式單例類(lèi)被加載時(shí)不會(huì)將自己實(shí)例化。如下圖所示,類(lèi)圖中給出了一個(gè)典型的餓漢式單例類(lèi)實(shí)現(xiàn)。



      代碼清單2:懶漢式單例類(lèi)

    package com.javapatterns.singleton.demos;
    public class LazySingleton
    {
    private static LazySingleton
    m_instance = null;
    /**
    * 私有的默認(rèn)構(gòu)造子,保證外界無(wú)法直接實(shí)例化
    */
    private LazySingleton() { }
    /**
    * 靜態(tài)工廠(chǎng)方法,返還此類(lèi)的惟一實(shí)例
    */
    synchronized public static LazySingleton
    getInstance()
    {
    if (m_instance == null)
    {
    m_instance = new LazySingleton();
    }
    return m_instance;
    }
    }


      讀者可能會(huì)注意到,在上面給出懶漢式單例類(lèi)實(shí)現(xiàn)里對(duì)靜態(tài)工廠(chǎng)方法使用了同步化,以處理多線(xiàn)程環(huán)境。有些設(shè)計(jì)師在這里建議使用所謂的"雙重檢查成例"。必須指出的是,"雙重檢查成例"不可以在Java 語(yǔ)言中使用。不十分熟悉的讀者,可以看看后面給出的小節(jié)。

      同樣,由于構(gòu)造子是私有的,因此,此類(lèi)不能被繼承。餓漢式單例類(lèi)在自己被加載時(shí)就將自己實(shí)例化。即便加載器是靜態(tài)的,在餓漢式單例類(lèi)被加載時(shí)仍會(huì)將自己實(shí)例化。單從資源利用效率角度來(lái)講,這個(gè)比懶漢式單例類(lèi)稍差些。

      從速度和反應(yīng)時(shí)間角度來(lái)講,則比懶漢式單例類(lèi)稍好些。然而,懶漢式單例類(lèi)在實(shí)例化時(shí), 必須處理好在多個(gè)線(xiàn)程同時(shí)首次引用此類(lèi)時(shí)的訪(fǎng)問(wèn)限制問(wèn)題,特別是當(dāng)單例類(lèi)作為資源控制器,在實(shí)例化時(shí)必然涉及資源初始化,而資源初始化很有可能耗費(fèi)時(shí)間。這意味著出現(xiàn)多線(xiàn)程同時(shí)首次引用此類(lèi)的機(jī)率變得較大。

      餓漢式單例類(lèi)可以在Java 語(yǔ)言?xún)?nèi)實(shí)現(xiàn), 但不易在C++ 內(nèi)實(shí)現(xiàn),因?yàn)殪o態(tài)初始化在C++ 里沒(méi)有固定的順序,因而靜態(tài)的m_instance 變量的初始化與類(lèi)的加載順序沒(méi)有保證,可能會(huì)出問(wèn)題。這就是為什么GoF 在提出單例類(lèi)的概念時(shí),舉的例子是懶漢式的。他們的書(shū)影響之大,以致Java 語(yǔ)言中單例類(lèi)的例子也大多是懶漢式的。實(shí)際上,本書(shū)認(rèn)為餓漢式單例類(lèi)更符合Java 語(yǔ)言本身的特點(diǎn)。


      登記式單例類(lèi)

      登記式單例類(lèi)是GoF 為了克服餓漢式單例類(lèi)及懶漢式單例類(lèi)均不可繼承的缺點(diǎn)而設(shè)計(jì)的。本書(shū)把他們的例子翻譯為Java 語(yǔ)言,并將它自己實(shí)例化的方式從懶漢式改為餓漢式。只是它的子類(lèi)實(shí)例化的方式只能是懶漢式的, 這是無(wú)法改變的。如下圖所示是登記式單例類(lèi)的一個(gè)例子,圖中的關(guān)系線(xiàn)表明,此類(lèi)已將自己實(shí)例化。



      代碼清單3:登記式單例類(lèi)

    import java.util.HashMap;
    public class RegSingleton
    {
    static private HashMap m_registry = new HashMap();
    static
    {
    RegSingleton x = new RegSingleton();
    m_registry.put( x.getClass().getName() , x);
    }
    /**
    * 保護(hù)的默認(rèn)構(gòu)造子
    */
    protected RegSingleton() {}
    /**
    * 靜態(tài)工廠(chǎng)方法,返還此類(lèi)惟一的實(shí)例
    */
    static public RegSingleton getInstance(String name)
    {
    if (name == null)
    {
    name = "com.javapatterns.singleton.demos.RegSingleton";
    }
    if (m_registry.get(name) == null)
    {
    try
    {
    m_registry.put( name,
    Class.forName(name).newInstance() ) ;
    }
    catch(Exception e)
    {
    System.out.println("Error happened.");
    }
    }
    return (RegSingleton) (m_registry.get(name) );
    }
    /**
    * 一個(gè)示意性的商業(yè)方法
    */
    public String about()
    {
    return "Hello, I am RegSingleton.";
    }
    }
      它的子類(lèi)RegSingletonChild 需要父類(lèi)的幫助才能實(shí)例化。下圖所示是登記式單例類(lèi)子類(lèi)的一個(gè)例子。圖中的關(guān)系表明,此類(lèi)是由父類(lèi)將子類(lèi)實(shí)例化的。



      下面是子類(lèi)的源代碼。

      代碼清單4:登記式單例類(lèi)的子類(lèi)

    import java.util.HashMap;
    public class RegSingletonChild extends RegSingleton
    {
    public RegSingletonChild() {}
    /**
    * 靜態(tài)工廠(chǎng)方法
    */
    static public RegSingletonChild getInstance()
    {
    return (RegSingletonChild)
    RegSingleton.getInstance(
    "com.javapatterns.singleton.demos.RegSingletonChild" );
    }
    /**
    * 一個(gè)示意性的商業(yè)方法
    */
    public String about()
    {
    return "Hello, I am RegSingletonChild.";
    }
    }


      在GoF 原始的例子中,并沒(méi)有g(shù)etInstance() 方法,這樣得到子類(lèi)必須調(diào)用的getInstance(String name)方法并傳入子類(lèi)的名字,因此很不方便。本章在登記式單例類(lèi)子類(lèi)的例子里,加入了getInstance() 方法,這樣做的好處是RegSingletonChild 可以通過(guò)這個(gè)方法,返還自已的實(shí)例。而這樣做的缺點(diǎn)是,由于數(shù)據(jù)類(lèi)型不同,無(wú)法在RegSingleton 提供這樣一個(gè)方法。由于子類(lèi)必須允許父類(lèi)以構(gòu)造子調(diào)用產(chǎn)生實(shí)例,因此,它的構(gòu)造子必須是公開(kāi)的。這樣一來(lái),就等于允許了以這樣方式產(chǎn)生實(shí)例而不在父類(lèi)的登記中。這是登記式單例類(lèi)的一個(gè)缺點(diǎn)。

      GoF 曾指出,由于父類(lèi)的實(shí)例必須存在才可能有子類(lèi)的實(shí)例,這在有些情況下是一個(gè)浪費(fèi)。這是登記式單例類(lèi)的另一個(gè)缺點(diǎn)。

    posted on 2005-04-18 14:37 笨笨 閱讀(209) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): J2EEALL
    主站蜘蛛池模板: 国产午夜无码精品免费看| 久久精品国产99精品国产亚洲性色| 无码av免费一区二区三区| 国产亚洲美女精品久久久久| 亚洲精品中文字幕无码AV| 亚洲自偷自偷图片| 国产成人免费福利网站| 国色精品卡一卡2卡3卡4卡免费| 久久大香伊焦在人线免费| rh男男车车的车车免费网站| 美女扒开尿口给男人爽免费视频 | 亚洲综合伊人制服丝袜美腿| 亚洲国产天堂在线观看| 亚洲日韩乱码中文无码蜜桃臀网站| 成人免费无码精品国产电影| 免费电视剧在线观看| 毛片免费全部播放无码| 无码av免费网站| 免费国产黄网站在线观看可以下载| 伊人久久大香线蕉免费视频| eeuss影院免费92242部| 一二三四在线观看免费中文在线观看| 亚洲AV无码一区二区三区性色| 亚洲AV男人的天堂在线观看| 亚洲二区在线视频| 亚洲av片不卡无码久久| 亚洲国产精品一区二区久| 亚洲综合激情视频| 亚洲欧洲国产精品久久| 亚洲Av高清一区二区三区| 亚洲www77777| 亚洲国产成人综合精品| 综合偷自拍亚洲乱中文字幕| 国产精品亚洲精品日韩动图| 亚洲成AV人片在WWW| 猫咪www免费人成网站| 日韩精品无码免费视频| 久久不见久久见免费影院www日本 久久WWW免费人成—看片 | 亚洲精品国产摄像头| WWW国产亚洲精品久久麻豆| 综合一区自拍亚洲综合图区|