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

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

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

    posts - 297,  comments - 1618,  trackbacks - 0

    1、   什么是單例模式?

          單例模式的意思就是只有一個實例。單例模式確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例。這個類稱為單例類。

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

    1)一個類只能有一個實例;

    2)自己創(chuàng)建這個實例;

    3)整個系統(tǒng)都要使用這個實例。

    單例模式的示意圖如下所示:
       

    在上面的對象圖中,有一個“單例對象”,而“客戶甲”、“客戶乙”和“客戶丙”是單例對象的三個客戶對象。可以看到,所有的客戶對象共享一個單例對象,而且從單例對象到自身的連接線可以看出,單例對象持有對自己的引用。

    2、   單例模式的應(yīng)用場景

    單例模式作為一種比較常見的設(shè)計模式,作用如下:

    1)控制資源的使用,通過線程同步來控制資源的并發(fā)訪問;

    2)控制實例產(chǎn)生的數(shù)量,達(dá)到節(jié)約資源的目的;

    3)作為通信媒介使用,也就是數(shù)據(jù)共享,它可以在不建立直接關(guān)聯(lián)的條件下,讓多個不相關(guān)的兩個線程或者進(jìn)程之間實現(xiàn)通信。

    單例模式常見的參考使用如下:

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

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

    3、   單例模式的兩種形式

    根據(jù)在建立單例對象的時間不同,可以形象的將單例模式分為兩種實現(xiàn)形式:“餓漢式”和“懶漢式”。

    3.1 “餓漢式”單例模式實現(xiàn)

    “餓漢式”是在不管你用的用不上,一開始就建立這個單例對象,例如如下Java代碼實現(xiàn)了餓漢式的單例模式:
    package singleton;

    /**
     * 餓漢式單例模式
     * @author AmigoXie
     */
    public class Singleton {
        private Singleton() {
            System.out.println("構(gòu)造器");
        }

        //在自己內(nèi)部定義自己一個實例,注意這是private 只供內(nèi)部調(diào)用
        private static Singleton instance = new Singleton();
        //這里提供了一個供外部訪問本class的靜態(tài)方法,可以直接訪問
        public static Singleton getInstance() {
            return instance;
        }

        public static void main(String[] args) {
            System.out.println("測試餓漢式單例模式");
            Singleton.getInstance();
        }
    }
    該例的運(yùn)行結(jié)果如下所示:
    構(gòu)造器
    測試餓漢式單例模式










    由此可知在調(diào)用單例對象的靜態(tài)方法getInstance()之前,構(gòu)造器Singleton()已被調(diào)用。

    3.2 “懶漢式”單例模式實現(xiàn)

    “懶漢式”是在你真正用到的時候才去建這個單例對象。,例如如下Java代碼實現(xiàn)了懶漢式的單例模式:
    package singleton;

    /**
     * 懶漢式單例模式
     * 
    @author AmigoXie
     
    */

    public class Singleton2 {
        
    private Singleton2() {
            System.out.println(
    "構(gòu)造器");
        }


        
    private static Singleton2 instance = null;

        
    public static synchronized Singleton2 getInstance() {
            
    //這個方法比上面有所改進(jìn),不用每次都進(jìn)行生成對象,只是第一次使用時生成實例
            if (instance == null{
            instance 
    = new Singleton2();
            }

            
    return instance;
        }


        
    public static void main(String[] args) {
            System.out.println(
    "測試懶漢式單例模式");
            Singleton2.getInstance();
        }

    }



         該例的運(yùn)行結(jié)果如下所示:

    測試懶漢式單例模式
    構(gòu)造器

         從運(yùn)行的打印結(jié)果表名,在getInstance()獲取實例方法被調(diào)用時,構(gòu)造器才被調(diào)用。

    4、   JavaScript中使用單例模式

    JavaScript中,單例(Singleton)模式是最基本又最有用的模式之一。這種模式提供了一種將代碼組織為一個邏輯單元的手段,這個邏輯單元中的代碼可以通過單一的變量進(jìn)行訪問。確保單例對象只有一份實例,你就可以確信自己的所有代碼使用的都是同樣的全局資源。

    單例類在JavaScript中用途廣泛:

    1)可以用來劃分命名空間,以減少網(wǎng)頁中全局變量的數(shù)量;

    2)可以在一種名為分支的技術(shù)中用來封裝瀏覽器之間的差異;

    3)可以借助于單例模式,將代碼組織得更為一致,從而使代碼更容易閱讀和維護(hù)。

    4.1 單例的基本結(jié)構(gòu)

    最基本的單例實際上是一個對象字面值,它將一批有一定關(guān)聯(lián)的方法和屬性組織在一起。例如如下JavaScript代碼:

    var Singleton = {
        attribute1: 
    true;
        attribute2: 
    10
        
        method1: 
    function() {
        }
    ,
        method2: 
    function() {
        }
       
    }
    ;

    這些成員可以通過Singleton加圓點(diǎn)運(yùn)算符來訪問:

    Singleton.attribute1 = false;
    var total = Singleton. attribute2 + 5;
    var result = Singleton.method1();

    對象字面值只是用以創(chuàng)建單例的方法之一,后面介紹的那些方法所創(chuàng)建的單體看起來更像其他面向?qū)ο笳Z言中的單例類。另外,并非所有對象字面值都是單體,如果它只是用來模仿關(guān)聯(lián)數(shù)組或容納數(shù)據(jù)的話,那顯然不是單例。但如果它是用來組織一批相關(guān)方法和屬性的話,那就可能是單例,其區(qū)別主要在于設(shè)計者的意圖。

    4.2 創(chuàng)建擁有私有成員的單例

    4.2.1 使用下劃線表示法

    在單例對象內(nèi)創(chuàng)建類的私有成員的最簡單、最直截了當(dāng)?shù)姆椒ㄊ鞘褂孟聞澗€表示法(在JavaScript業(yè)界,如果變量和方法是使用下劃線,則表示該變量和方法是私有方法,只允許內(nèi)部調(diào)用,第三方不應(yīng)該去調(diào)用)。參考實例如下:

    GiantCorp.DataParser = {
        
    // 私有方法
        _stripWhitespace: function(str) {
            
    return str.replace(/\s+/, ''); 
        }
    ,
        _stringSplit: 
    function(str, delimiter) {
            
    return str.split(delimiter);
        }
    ,

        
    // 公用方法
        stringToArray: function(str, delimiter, stripWS) {
            
    if (stripWS) {
                str 
    = this._stripWhitespace(str);
            }

            
            
    var outputArray = this._stringSplit(str, delimiter);
            
    return outputArray;
        }

    }
    ;

    在如上代碼中,stringToArray方法中使用this訪問單體中的其他方法,這是訪問單體中其他成員或方法的最簡便的方法。但這樣做有一點(diǎn)風(fēng)險,因為this并不一定指向GiantCorp.DataParser例如,如果把某個方法用作事件監(jiān)聽器,那么其中的this指向的是window對象,因此大多數(shù)JavaScript庫都會為事件關(guān)聯(lián)進(jìn)行作用域校正,例如在這里使用GiantCorp.DataParser比使用this更為安全。

    4.2.2使用閉包

    在單例對象中創(chuàng)建私有成員的第二種方法是借助閉包。因為單例只會被實例化一次,所以不必?fù)?dān)心自己在構(gòu)造函數(shù)中聲明了多少成員。每個方法和屬性都只會被創(chuàng)建一次,所以可以把它們聲明在構(gòu)造函數(shù)內(nèi)部(因此也就位于同一個閉包中)。

    使用閉包創(chuàng)建擁有私有成員的單例類的實例如下:

    MyNamespace.Ssingleton = (function() {
        
    // 私有成員
         var privateAttribute1 = false;
        
    var privateAttribute2 = [123];
     
        
    function privateMethod1() {
            
        }
        

        
    function privateMethod2() {
            
        }

     
        
    return {
            
    // 公有成員
            publicAttribute1: true;
            publicAttribute2: 
    10,
            
            publicMethod1: 
    function() {
                
            }
    ,
            publicMethod2: 
    function() {
                
            }

        }
    ;
    }
    )();

    這種單例模式又稱為模塊模式,指的是它可以把一批相關(guān)方法和屬性組織為模塊并起到劃分命名空間的作用。

    使用該種方式改造4.2.1中的實例,參考代碼如下:

    GiantCorp.DataParser = (function() {
        
    var whiteSpaceRegex = /\s+/;
        
    // 私有方法
        function stripWhitespace(str) {
            
    return str.replace(whiteSpaceRegex, ''); 
        }


        
    function stringSplit(str, delimiter) {
            
    return str.split(delimiter);
        }
    ,

        
    return {
            
    // 公用方法
            stringToArray: function(str, delimiter, stripWS) {
                
    if (stripWS) {
                    str 
    = stripWhitespace(str);
                }

                
                
    var outputArray = stringSplit(str, delimiter);
                
    return outputArray;
            }

        }
    ;
    }
    )();

    將私有成員放在閉包中可以確保其不會在單例對象之外被使用,因此開發(fā)人員可以自由的改變對象的實現(xiàn)細(xì)節(jié),而不會殃及別人的代碼。還可以使用這種辦法對數(shù)據(jù)進(jìn)行保護(hù)和封裝。

    4.3 JavaScript中實現(xiàn)“懶漢式”單例模式

    在如上的代碼中,單例對象都是在腳本加載時被創(chuàng)建出來。對于資源密集型或配置開銷甚大的單例,更合理的是使用3.2小節(jié)中提到的“懶漢式”單例實現(xiàn)。這種實現(xiàn)方式的特別之處在于,對它們的訪問必須借助于一個靜態(tài)方法,例如調(diào)用單例類的getInstance()方法獲得對象實例。

    參考實現(xiàn)代碼如下:

    MyNamespace.Singleton = (function() {
        
    // 定義一個私有的屬性,該屬性用于儲存單例對象
        var uniqueInstance;
        
    function constructor() {
            
    // 將單態(tài)操作放在這里
            
        }


        
    return {
            getInstance: 
    function() {
                
    if (!uniqueInstance) {
                    uniqueInstance 
    = constructor();
                }

               
                
    return uniqueInstance;
            }

        }

    }
    )();

    將一個單例轉(zhuǎn)換為懶漢式加載方式后,必須對調(diào)用它的代碼進(jìn)行修改,例如之前調(diào)用:

    MyNamespace.Singleton.publicMethod1();

    應(yīng)該改成如下代碼:

    MyNamespace.Singleton.getInstance().publicMethod1();

    如果覺得命名空間名稱太長,可以創(chuàng)建一個別名來簡化它。

    4.4 使用單例模式實現(xiàn)分支

    分支是一種用來把瀏覽器之間的差異封裝到運(yùn)行期間進(jìn)行設(shè)置的動態(tài)方法中的技術(shù)。例如,假設(shè)我們需要一個創(chuàng)建XHR對象的方法,這種XHR對象在大多數(shù)瀏覽器中是XMLHttpRequest對象的實例,但在IE早期版本中是某種ActiveX類的實例,這樣一種方法通常會進(jìn)行某種瀏覽器嗅探或?qū)ο筇綔y。如果不用分支技術(shù),那么每次調(diào)用這個方法時,所有這些瀏覽器嗅探代碼都要再次運(yùn)行。如果該方法調(diào)用頻繁,將會嚴(yán)重影響效率。

    要實現(xiàn)獲取不同瀏覽器的XHR對象的功能,參考實現(xiàn)代碼的實現(xiàn)步驟如下:

    1)判斷有多少個分支(有3個),這些分支按其返回的XHR對象類型命名,這三個分支都有一個名為createXhrObject()的方法,該方法返回一個可以執(zhí)行異步請求的新對象;

    2)根據(jù)條件將3個分支中某一分支的對象賦給那個變量,具體做法是逐一嘗試XHR對象,直到遇到一個當(dāng)前JavaScript環(huán)境所支持的對象為止。

    參考代碼如下所示:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
        
    <head>
            
    <title>使用單例模式實現(xiàn)JavaScript中的分支</title>
            
    <script type="text/javascript">
                
    var SimpleXhrFactory = (function() {
                    
    // 三個分支
                    var standard = {
                        createXhrObject: 
    function() {
                            alert(
    "standard createXhrObject");
                            
    return new XMLHttpRequest();
                        }

                    }
    ;
                    
    var activeXNew = {
                        createXhrObject: 
    function() {
                            alert(
    "activeXNew createXhrObject");
                            
    return new ActiveXObject("Msxml2.XMLHTTP");
                        }

                    }
    ;
                    
    var activeXOld = {
                        createXhrObject: 
    function() {
                            alert(
    "activeXOld createXhrObject");
                            
    return new ActiveXObject("Microsoft.XMLHTTP");
                        }

                    }
    ;

                    
    // 為分支賦值
                    var testObject;
                    
    try {
                        testObject 
    = standard.createXhrObject();
                        
    return standard;
                    }
     catch(e) {
                        
    try {
                            testObject 
    = activeXNew.createXhrObject();
                            
    return activeXNew;
                        }
     catch(e) {
                            
    try {
                                testObject 
    = activeXOld.createXhrObject();
                                
    return activeXOld;
                            }
     catch(e) {
                                
    throw new Error("在該瀏覽器環(huán)境中沒有發(fā)現(xiàn)XHR對象.");
                            }

                        }

                    }
     
                }
    )();

                SimpleXhrFactory.createXhrObject();

            
    </script>

        
    </head>

        
    <body>

        
    </body>

    </html>

    用了分支技術(shù)后,所有的那些特性嗅探代碼都只會執(zhí)行一次,而不是沒生成一個對象執(zhí)行一次。這種技術(shù)適用于任何只有在運(yùn)行時才能確定具體實現(xiàn)的情況。 

    5、   單例模式的優(yōu)缺點(diǎn)

          JavaScript中使用單例模式的主要優(yōu)點(diǎn)如下:

    1)對代碼的組織作用:它將相關(guān)方法和屬性組織在一個不會被多次實例話的單例中,可以使代碼的調(diào)試和維護(hù)變得更輕松。描述性的命名空間還可以增強(qiáng)代碼的自我說明性。將方法包裹在單例中,可以防止它們被其它程序員誤改。

    2)單例模式的一些高級變體可以在開發(fā)周期的后期用于對腳本進(jìn)行優(yōu)化。

    主要缺點(diǎn)如下:

    1)因為提供的是一種單點(diǎn)訪問,所以它有可能導(dǎo)致模塊間的強(qiáng)耦合。單體最好是留給定義命名空間和實現(xiàn)分支型方法這些用途,這些情況下,耦合不是什么問題;

    2)有時某些更高級的模式會更符合任務(wù)的需要。與“懶漢式”加載單例相比,虛擬代理能給予你對實例化方式更多的控制權(quán)。也可以用一個真正的對象工廠來取代分支型單例。

    6、   參考文檔

    1)《JavaScript設(shè)計模式》 Ross HarmesDustin Dial著,謝廷晟 譯,人民郵電出版社出版

    2)《單例模式_百度百科》:

    http://baike.baidu.com/view/1859857.htm

     

     

    posted on 2011-11-07 13:14 阿蜜果 閱讀(3108) 評論(3)  編輯  收藏 所屬分類: JavascriptDesign Pattern


    FeedBack:
    # re: 蜜果私塾:在JavaScript中使用單例模式
    2011-11-09 20:16 | 博洋家紡
    有時某些更高級的模式會更符合任務(wù)的需要。與“懶漢式”加載單例相比,虛擬代理能給予你對實例化方式更多的控制權(quán)。也可以用一個真正的對象工廠來取代分支型單例。
      回復(fù)  更多評論
      
    # re: 蜜果私塾:在JavaScript中使用單例模式
    2011-11-10 08:10 | tbw
    不錯 學(xué)習(xí)了   回復(fù)  更多評論
      
    # re: 蜜果私塾:在JavaScript中使用單例模式
    2011-11-10 14:47 | tbw淘寶
    嘗到新東西  回復(fù)  更多評論
      
    <2011年11月>
    303112345
    6789101112
    13141516171819
    20212223242526
    27282930123
    45678910

          生活將我們磨圓,是為了讓我們滾得更遠(yuǎn)——“圓”來如此。
          我的作品:
          玩轉(zhuǎn)Axure RP  (2015年12月出版)
          

          Power Designer系統(tǒng)分析與建模實戰(zhàn)  (2015年7月出版)
          
         Struts2+Hibernate3+Spring2   (2010年5月出版)
         

    留言簿(263)

    隨筆分類

    隨筆檔案

    文章分類

    相冊

    關(guān)注blog

    積分與排名

    • 積分 - 2298116
    • 排名 - 3

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 77777亚洲午夜久久多喷| 亚洲一区二区三区免费观看| 国产精品亚洲综合专区片高清久久久| 亚洲码国产精品高潮在线| 亚洲不卡在线观看| 真实国产乱子伦精品免费| 日本免费电影一区| 亚洲AV日韩精品久久久久久久 | 亚洲中久无码永久在线观看同| 亚洲一二成人精品区| 在线电影你懂的亚洲| 又长又大又粗又硬3p免费视频 | 最新亚洲精品国偷自产在线| 国产精品成人69XXX免费视频| 99久久99这里只有免费费精品| 亚洲一区二区三区在线视频| 亚洲jizzjizz在线播放久| 久久不见久久见中文字幕免费| 久久久久亚洲AV片无码| 久久这里只精品99re免费| 免费人妻无码不卡中文字幕18禁| 亚洲春色另类小说| 久久午夜羞羞影院免费观看| 色久悠悠婷婷综合在线亚洲| 国产精品偷伦视频观看免费 | 91精品导航在线网址免费| 亚洲成a人片7777| 日本免费人成黄页在线观看视频 | 亚洲AV无码第一区二区三区| 麻豆一区二区三区蜜桃免费| 天天摸夜夜摸成人免费视频 | 免费观看亚洲人成网站| 日韩成人免费aa在线看| 一级黄色毛片免费看| 国产一级淫片a视频免费观看| 亚洲综合av一区二区三区不卡| 亚洲一区免费在线观看| 亚洲一区二区三区日本久久九| 国产桃色在线成免费视频 | 免费va人成视频网站全| 免费看男人j放进女人j免费看|