天天看點

JavaScript設計模式學習(四)單件(Singleton Pattern)

單件是JavaScript中最基本、最有用的設計模式,而你今後也會經常的使用這個模式。通過單件,我們可以把統一到一個邏輯單元中并且提供一個唯一的入口,這就保證你所有的引用都是用的這個全局資源。

單件的用途有:一、提供一個Namespacing、二、提供一種被稱為branching的技術。

單件的基本形式:

/* Basic Singleton Pattern */

var

Map

=

{

    name:"Map G",

    createdate:"2008-09-19",

    sayMyName:function(){

        alert("My Name is "

+

this.name);

    },

    tellMeWords:function(arg){

        alert("What you told to me is "

arg

"\n I won't tell anyone!")

    }

}

命名空間:

我們可以給單件提供新的屬性,并且能夠建立獨立的命名空間,而避免我們寫的屬性或者程式被無意的覆寫。我們接着單件的基本形式中的例子可以建立新的屬性:

Map.Property

    createdata:"2000-09-09",

    width:"100",

    height:"200"

Map.Utility

    getSize:function(x,y){

        return

x*y;

這樣,同樣的createdate屬性即便一樣,也不會造成程式中的沖突了。

在單件中添加私有成員:

利用下劃線。最簡單、最直接的聲明私有變量的方式就是使用下劃線。這樣就可以使其他程式員明白,這些變量是私有的、隻是在對象内部使用,同時也可以使其他程式員避免直接通路他們。

    _isMature:function(){

        alert("Of Course, I'm Mature!");

使用Closure。

使用Closure,我們可以實作私有變量和共有變量。因為singleton在調用過程中隻會有一個執行個體,是以我們就不必擔心私有成員耗費資源的問題了。例子如下:

MyNamespace

{};

MyNamespace.Singleton

(function(){

    var

privateAttribute1

"Name";

privateAttribute2

true;

    function

privateMethod1(){

    return

        publicAttribute1:"Public",

        publicAttribute2:"false",

        publicMethod1:function(){

        }

    };

})();

Lazy Instantiation

以上所讨論的各種各樣的單件實作,他們都有一個共同點,那就是當代碼加載時就立即建立的。如果你有一個需要複雜配置的單件、或者他加載的時候需要占用大量資源,也許我們就該考慮延時實作他了。Lazy Loading就是用來解決這個問題的,常被用在需要加載大量資料的時候。

Lazy Loading singletons與之前的singleton不同,你不能通過MyNamespace.methdName()來進行通路,而必須通過Mynamespace.getInstance().methodName()來通路。GetInstance方法首先檢查單件是否進行執行個體化,如果沒有,則建立并傳回,下面是例子:

//Lazy instantiation

Car

Car.MyPorsche

uniqueInstance;

CarOfPorsche(){

        var

name

"My Favorate Porsche";

buydate

"2008-09-22";

            speed:"120Kmp",

            getName:function(){

                return

name;

            }

        };

        getInstance:function(){

            if(!uniqueInstance){

                uniqueInstance

CarOfPorsche();

            return

//Normal Singleton

Car.MyBenz

"My Benz Car";

"2009-10-10";

        speed:"140Kmp",

        getName:function(){

Lazy loading的一個缺點是增加了代碼的複雜性,而且代碼開始變得難以了解。在調用的時候,我們需要通過Car.MyPorsche.getInstance().speed來調用,這就增加了代碼的複雜行。當然,我們可以通過

            var

porsche

Car.MyPorsche.getInstance();

            alert(porsche.getName()

"'s speed is "

porsche.speed);

來簡化調用。

分支(Branching):

分支是一項将不同浏覽器的差別封裝到動态方法中的技術。我們以建立XHR對象為例。對于大多數浏覽器,XHR 是XMLHttpRequest對象的一個執行個體,或者是較早版本的IE的不同ActiveX的一個執行個體。這個方法總是伴随着對于浏覽器的檢測,如果我們沒用用Branching這項技術,沒次我們都需要運作浏覽器檢測的方法來檢查,這降低了代碼的效率。

一個更加高效的方式就是當代碼加載時,根據浏覽器的不同賦予一個固定的值,在不同的浏覽器下,我們隻執行這個實作的擴充。在運作時刻動态改變一個Function的内容,這正是JavaScript靈活的強大的所在。

那麼分支如何應用在單件中呢,看下面的例子:

//Branching

//SimpleXhrFactory Singleton

SimpleXhrFactory

standard

        createObject:function(){

new

XMLHttpRequest();

activexNew

ActiveXObject("Msxml2.XMLHTTP");

activexOld

ActiveXObject("Microsoft.XMLHTTP");

testObject;

    try{

        testObject

standard.createObject();

standard;

    }catch(e){

        try{

            testObject

activexNew.createObject();

activexNew;

        }catch(e){

            try{

                testObject

activexOld.createObject();

activexOld;

            }catch(e){

                throw

Error("No XMLHTTP Object found in this environment!");

什麼時候使用單件:

當需要使用命名空間或者子產品化你的代碼的時候,應該盡量的使用單件。單件是JavaScript中使用最廣泛的一個設計模式,無論在什麼規模的項目中,你都能看到他的影子。

使用單件的好處:

單件的主要作用是提供了一個格式化你的代碼的方法。通過吧相似的方法和屬性集合到一個單間中,并且隻能被執行個體化一次,你就可以更友善的調試代碼。

繼續閱讀