国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript設(shè)計模式

mingzhong / 1239人閱讀

摘要:依賴于接口的設(shè)計模式下面列出的設(shè)計模式,尤其依賴接口工廠模式。這些私用的靜態(tài)成員可以從構(gòu)造器內(nèi)部訪問,這意味著所有私用函數(shù)和特權(quán)函數(shù)都能訪問它們。構(gòu)造器靜態(tài)特權(quán)方法封裝之弊私用方法很難進(jìn)行單元測試。

1.弱類型語言

在JavaScript中,定義變量時不必聲明其類型。但這并不意味著變量沒有類型。一個變量可以屬于幾種類型之一,這取決于其包含的數(shù)據(jù)。JavaScript中有三種原始類型:布爾型、數(shù)值型和字符串類型(不區(qū)分整數(shù)和浮點(diǎn)數(shù)是JavaScript與大多數(shù)其他主流語言的一個不同之處)。此外,還有對象類型和包含可執(zhí)行代碼的函數(shù)類型,前者是一種復(fù)合數(shù)據(jù)類型(數(shù)組是一種特殊的對象,它包含著一批值的有序集合)。最后,還有空類型(null)未定義類型(undefined)這兩種數(shù)據(jù)類型。原始數(shù)據(jù)類型按值傳送,而其他數(shù)據(jù)類型則按引用傳送。

與其他弱類型語言一樣,JavaScript中的變量可以根據(jù)所賦的值改變類型。原始類型之間也可以進(jìn)行類型轉(zhuǎn)換。toString可以把數(shù)值或布爾值轉(zhuǎn)為字符串。parseFloat和parseInt函數(shù)可以把字符串轉(zhuǎn)變?yōu)閿?shù)值。雙重“非”可以把字符串或數(shù)值轉(zhuǎn)變?yōu)椴紶栔担?b>var bool = !!num;

2.初談閉包
匿名函數(shù)最有趣的用途是用來創(chuàng)建閉包。閉包是一個受到保護(hù)的變量空間,由內(nèi)嵌函數(shù)生成。JavaScript具有函數(shù)級的作用域。這意味著定義在函數(shù)內(nèi)部的變量在函數(shù)外部不能被訪問。JavaScript的作用域又是詞法性質(zhì)的。這意味著函數(shù)運(yùn)行在定義它的作用域中,而不是在調(diào)用它的作用域中。把這兩個因素結(jié)合起來,就能通過把變量包裹在匿名函數(shù)中而對其加以保護(hù)。
3.依賴于接口的設(shè)計模式

下面列出的設(shè)計模式,尤其依賴接口:

工廠模式。對象工廠所創(chuàng)建的具體對象會因具體情況而異。使用接口可以確保所創(chuàng)建出來的這些對象可以互換使用。也就是說,對象工廠可以保證其生產(chǎn)出來的對象都實(shí)現(xiàn)了必需的方法。

組合模式。如果不用接口你就不可能用這個模式。組合模式的中心思想在于可以將對象群體與其組成對象同等對待。這是通過讓它們實(shí)現(xiàn)同樣的接口來做到的。如果不進(jìn)行某種形式的鴨式辨型或類型檢查,組合模式就會失去大部分作用。

裝飾者模式。裝飾者通過透明地為另一對象提供包裝而發(fā)揮作用。這是通過實(shí)現(xiàn)與另外那個對象完全相同的接口而做到的。對于外界而言,一個裝飾者和它所包裝的對象看不出有什么區(qū)別。

命令模式。代碼中所有的命令對象都要實(shí)現(xiàn)同一批方法。通過使用接口,你為執(zhí)行這些命令對象而創(chuàng)建的類可以不必知道這些對象具體是什么,只要知道它們都實(shí)現(xiàn)了正確的接口即可。

4.用命名規(guī)范區(qū)別私用成員
在一些方法和屬性的名稱前面加下劃線以示其私用性。下劃線的這種用法是一個眾所周知的命名規(guī)范,它表明一個屬性(或方法)僅供對象內(nèi)部使用,直接訪問它或設(shè)置它可能會導(dǎo)致意想不到的后果。這有助于防止程序員對它的無意使用,卻不能防止對它的有意使用。后一個目標(biāo)的實(shí)現(xiàn)需要有真正私用性的方法。
5.作用域

下面這個示例說明了JavaScript中作用域的特點(diǎn):

function foo() {
    var a = 10;

    function bar() {
        a *= 2;
    }

    bar();
    return a;
}

在這個示例中,a定義在函數(shù)foo中,但函數(shù)bar可以訪問它,因為bar也定義在foo中。bar在執(zhí)行過程中將a設(shè)置為a乘以2。當(dāng)bar在foo中被調(diào)用時它能夠訪問a,這可以理解。但是如果bar是在foo外部被調(diào)用呢?

function foo() {
    var a = 10;

    function bar() {
        a *= 2;
        return a;
    }

    return bar;
}

var baz = foo();
console.log(baz());//20
console.log(baz());//40
console.log(baz());//80

var blat = foo();
console.log(blat());//20

在上述代碼中,所返回的對bar函數(shù)的引用被賦給變量baz。這個函數(shù)現(xiàn)在是在foo外部被調(diào)用,但它依然能夠訪問a。這是因為JavaScript的作用域是詞法性的。函數(shù)是運(yùn)行在定義它們的作用域中(本例中是foo內(nèi)部的作用域),而不是運(yùn)行在調(diào)用它們的作用域中。只要bar被定義在foo中,它就能訪問在foo中定義的所有變量,即使foo的執(zhí)行已經(jīng)結(jié)束。
這就是閉包的一個例子。在foo返回后,它的作用域被保存下來,但只有它返回的那個函數(shù)能夠訪問這個作用域。在前面的示例中,baz和blat各有這個作用域及a的一個副本,而且只有它們自己能對其進(jìn)行修改。返回一個內(nèi)嵌函數(shù)是創(chuàng)建閉包最常用的手段。

6.用閉包實(shí)現(xiàn)私用成員的弊端
在門戶打開型對象創(chuàng)建模式中,所有方法都創(chuàng)建在原型對象中,因此不管派生多少對象實(shí)例,這些方法在內(nèi)存中只存在一份。而包含特權(quán)方法、私用成員的創(chuàng)建模式中,每生成一個新的對象示例都將為每一個私用方法和特權(quán)方法生成一個新的副本。這會比其他做法耗費(fèi)更多內(nèi)存,所以只宜用在需要真正的私用成員的場合。這種對象創(chuàng)建模式也不利于派生子類,因為所派生出的子類不能訪問超類的任何私用屬性或方法。相比之下,在大多數(shù)語言中,子類都能訪問超類的所有私有屬性和方法。故在JavaScript中用閉包實(shí)現(xiàn)私用成員導(dǎo)致的派生問題稱為“繼承破壞封裝”。
7.靜態(tài)方法和屬性
前面所講的作用域和閉包的概念可用于創(chuàng)建靜態(tài)成員,包括公用和私用的。大多數(shù)方法和屬性所關(guān)聯(lián)的是類的實(shí)例,而靜態(tài)成員所關(guān)聯(lián)的則是類本身。換句話說,靜態(tài)成員是在累的層次上操作,而不是在實(shí)例的層次上操作。每個靜態(tài)成員都只有一份。稍后將會看到,靜態(tài)成員是直接通過類對象訪問的。
下面是添加了靜態(tài)屬性和方法的Book類:
var Book = (function () {

    //私有靜態(tài)變量
    var numOfBooks = 0;

    //私有靜態(tài)方法
    function checkIsbn(isbn) {

    }

    //返回一個構(gòu)造器
    return function (newIsbn, newTitle, newAuthor) {
        //私有屬性
        var isbn, title, author;

        //特權(quán)方法
        this.getIsbn = function () {
            return isbn;
        };
        this.setIsbn = function (newIsbn) {
            if (!checkIsbn(newIsbn)) {
                throw new Error("Book: Invalid ISBN.");
            }
            isbn = newIsbn;
        };
        this.getTitle = function () {
            return title;
        };
        this.setTitle = function (newTitle) {
            title = newTitle || "No title specified";
        };
        this.getAuthor = function () {
            return author;
        };
        this.setAuthor = function (newAuthor) {
            author = newAuthor || "No author specified";
        };

        //Constructed code.
        numOfBooks++;
        if (numOfBooks > 50) {
            throw new Error(".");
        }
        this.setIsbn(newIsbn);
        this.setTitle(newTitle);
        this.setAuthor(newAuthor);
    }
})();

//公共靜態(tài)方法
Book.convertToTitleCase = function (inputString) {

};

//公共非特權(quán)方法
Book.prototype = {
    display: function () {

    }
};

這里的私用成員和特權(quán)成員仍然被聲明在構(gòu)造器中(分別使用var和this關(guān)鍵字)。但哪個構(gòu)造器卻從原來的普通函數(shù)變成了一個內(nèi)嵌函數(shù),并且被作為包含它的函數(shù)的返回值賦給變量Book。這就創(chuàng)建了一個閉包,你可以把靜態(tài)的私用成員聲明在里面。位于外層函數(shù)聲明之后的一對空括號很重要,其作用是一段代碼載入就立即執(zhí)行這個函數(shù)(而不是在調(diào)用Book構(gòu)造函數(shù)時)。這個函數(shù)的返回值是另一個函數(shù),它被賦給Book變量,Book因此成了一個構(gòu)造函數(shù)。在實(shí)例化Book時,所調(diào)用的是這個內(nèi)層函數(shù)。外層那個函數(shù)只是用于創(chuàng)建一個可以用來存放靜態(tài)私用成員的閉包。

在本例中,checkIsbn被設(shè)計為靜態(tài)方法 ,原因是為Book的每個實(shí)例都生成這個方法的一個新副本毫無道理。此外還有一個靜態(tài)屬性numOfBooks,其作用在于跟蹤Book構(gòu)造器的總調(diào)用次數(shù)。本例利用這個屬性將Book實(shí)例的個數(shù)限制為不超過50個。

這些私用的靜態(tài)成員可以從構(gòu)造器內(nèi)部訪問,這意味著所有私用函數(shù)和特權(quán)函數(shù)都能訪問它們。與其他方法相比,它們有一個明顯的優(yōu)點(diǎn),那就是內(nèi)存中只會存放一份。因為其中那些靜態(tài)方法被聲明在構(gòu)造器之外,所以它們不是特權(quán)方法,不能訪問任何定義在構(gòu)造器中的私用屬性。定義在構(gòu)造器中的私用方法能夠調(diào)用那些私用靜態(tài)方法,反之則不然。要判斷一個私用方法是否應(yīng)該被設(shè)計為靜態(tài)方法,一條經(jīng)驗法則是看它是否需要訪問任何實(shí)例數(shù)據(jù)。如果它不需要,那么將其設(shè)計為靜態(tài)方法會更有效率(從內(nèi)存占用的意義上來講),因為它只會被創(chuàng)建一份。

創(chuàng)建公用的靜態(tài)成員則容易得多,只需直接將其作為構(gòu)造函數(shù)這個對象的屬性創(chuàng)建即可,前述代碼中的方法converToTitleCase就是一例。這實(shí)際上相當(dāng)于把構(gòu)造器作為命名空間來使用。

所有公用靜態(tài)方法如果作為獨(dú)立的函數(shù)來聲明其實(shí)也同樣簡單,但最好還是像這樣把相關(guān)行為集中在一起。這些方法用于與類這個整體相關(guān)的任務(wù),而不是與類的任一特定實(shí)例相關(guān)的任務(wù)。它們并不直接依賴于對象實(shí)例中包含的任何數(shù)據(jù)。

8.私用變量模仿常量
通過創(chuàng)建只有取值器而沒有賦值器的私用變量可以模仿常量。
var Class = (function () {
    var UPPER_BOUND = 100;

    //構(gòu)造器
    var ctor = function (constructorArgument) {

    };
    //靜態(tài)特權(quán)方法
    ctor.getUPPER_BOUND = function () {
        return UPPER_BOUND;
    };
    return ctor;

})();
9.封裝之弊

私用方法很難進(jìn)行單元測試。因為它們及其內(nèi)部變量都是私用的,所以在對象外部無法訪問到它們。這個問題沒有什么很好的應(yīng)對之策。你要么通過使用公用方法來提供訪問途徑(這樣一來就葬送了使用私有方法所帶來的大多數(shù)好處),要么設(shè)法在對象內(nèi)部定義并執(zhí)行所有單元測試。最好的解決辦法是只對公用方法進(jìn)行單元測試。這應(yīng)該能覆蓋到所有私用方法,盡管對它們的測試只是間接的。這種問題不是JavaScript所獨(dú)有的,只對公用方法進(jìn)行單元測試是一種廣為接收的處理方式。

使用封裝意味著不得不與復(fù)雜的作用域鏈打交道。

封裝可能會損害類的靈活性,致使其無法被用于某些你未曾想到過的目的。

10.單體模式
單體模式是JavaScript中最基本但又最有用的模式之一,它可能比其他任何模式都更常用。這種模式提供了一種將代碼組織為一個邏輯單元的手段,這個邏輯單元中的代碼可以通過單一的變量進(jìn)行訪問。通過確保單體對象只存在一份實(shí)例,你就可以確信自己的所有代碼使用的都是同樣的全局資源。
單體類在JavaScript中有許多用處。它們可以用來劃分命名空間,以減少網(wǎng)頁中全局變量的數(shù)目。更重要的是,借助于單體模式,你可以把代碼組織得更為一致,從而使其更容易閱讀和維護(hù)。
11.單體的基本結(jié)構(gòu)
var Singleton = {
    attribute1: true,
    attribute2: 10,
    method1: function () {

    },
    method2: function (args) {

    }
};

這個單體對象可以被修改。你可以為其添加新成員,這一點(diǎn)與別的對象字面量沒有什么不同。你也可以用delete運(yùn)算符刪除其現(xiàn)有成員。這實(shí)際上違背了面向?qū)ο笤O(shè)計的一條原則:類可以被擴(kuò)展,但不應(yīng)該被修改。

按傳統(tǒng)的定義,單體是一個只能被實(shí)例化一次并且可以通過一個眾所周知的訪問點(diǎn)訪問的類。要是嚴(yán)格按照這個定義來說,前面的例子所示的并不是一個單體,因為它不是一個可實(shí)例化的類。我們打算把單體模式定義的更廣義一些:單體是一個用來劃分命名空間并將一批相關(guān)方法和屬性組織在一起的對象,如果可以被實(shí)例化,那么它只能被實(shí)例化一次。

12.劃分命名空間

為了避免無意中改寫變量,最好的解決辦法之一是用單體對象將代碼組織在命名空間之中。下面是前面的例子用單體模式改良后的結(jié)果:

var MyNamespace = {
    findProduct: function (id) {

    }
};

現(xiàn)在findProduct函數(shù)是MyNamespace中的一個方法,它不會被全局命名空間中聲明的任何新變量改寫。要注意,該方法仍然可以從各個地方訪問。不同之處在于現(xiàn)在其調(diào)用方式不是findProduct(id),而是MyNamespace.findProduct(id)。還有一個好處就是,這可以讓其他程序員大體知道這個方法的聲明地點(diǎn)及其作用。用命名空間把類似的方法組織到一起,也有助于增強(qiáng)代碼的文檔性。

13.模塊模式
有一種單體模式被稱為模塊模式,因為它可以把一批相關(guān)方法和屬性組織為模塊并起到劃分命名空間的作用。例如:
MyNamespace.Singleton = (function () {
    //私有成員
    var privateAttribute1 = false;
    var privateAttribute2 = [1, 2, 3];

    function privateMethod1() {

    }

    function privateMethod2() {

    }

    return {
        //public members
        publicAttribute1: true,
        publicAttribute2: 10,
        publicMethod1: function () {

        },
        publicMethod2: function (args) {

        }
    }
})();
14.簡單工廠模式
最好用一個例子來說明簡單工廠模式的概念。假設(shè)你想開幾個自行車商店,每個店都有幾種型號的自行車出售。這可以用一個類來表示:
/*BicycleShop class.*/
var BicycleShop = function () {

};

BicycleShop.prototype = {
    sellBicycle: function (model) {
        var bicycle;
        switch (model) {
            case "The Speedster":
                bicycle = new SpeedSter();
                break;
            case "The Lowrider":
                bicycle = new Lowrider();
                break;
            case "The Comfort Cruiser":
            default:
                bicycle = new ComfortCruiser();
        }
        Interface.ensureImplements(bicycle, Bicycle);
        bicycle.assemble();
        bicycle.wash();
        return bicycle;
    }
};
sellBicycle方法根據(jù)所要求的自行車型號用switch語句創(chuàng)建一個自行車的實(shí)例。各種型號的自行車實(shí)例可以互換使用,因為它們都實(shí)現(xiàn)了Bicycle接口:
/* The Bicycle interface. */
var Bicycle = new Interface("Bicycle", ["assemble", "wash", "ride", "repair"]);

/* Speedster class. */
var Speedster = function () {

};
Speedster.prototype = {
    assemble: function () {
    },
    wash: function () {
    },
    ride: function () {
    },
    repair: function () {
    }
};
要出售某種型號的自行車,只要調(diào)用sellBicycle方法即可:
var californiaCruisers = new BicycleShop();
var yourNewBike = californiaCruisers.sellBicycle("The Speedster");
在情況發(fā)生變化之前,這倒也挺管用。但要是你想在供貨目錄中加入一款新車型又會怎么樣呢?你得為此修改BicycleShop的代碼,哪怕這個類的實(shí)際功能實(shí)際上并沒有發(fā)生改變——依舊是創(chuàng)建一個自行車的新實(shí)例,組裝它,清洗它,然后把它交給顧客。更好的解決辦法是把sellBicycle方法中“創(chuàng)建新實(shí)例”這部分工作轉(zhuǎn)交給一個簡單工廠對象:
/* BicycleFactory namespace. */
var BicycleFactory = {
    createBicycle:function(model){
        var bicycle;
        switch (model) {
            case "The Speedster":
                bicycle = new SpeedSter();
                break;
            case "The Lowrider":
                bicycle = new Lowrider();
                break;
            case "The Comfort Cruiser":
            default:
                bicycle = new ComfortCruiser();
        }
        Interface.ensureImplements(bicycle, Bicycle);
        return bicycle;
    }
};

BicycleFactory是一個單體,用來把createBicycle方法封裝在一個命名空間中。這個方法返回一個實(shí)現(xiàn)了Bicycle接口的對象,然后你可以照常對其進(jìn)行組裝和清洗:

/* BicycleShop class, improved. */
var BicycleShop = function () {
};
BicycleShop.prototype = {
    sellBicycle: function (model) {
        var bicycle = BicycleFactory.createBicycle(model);
        bicycle.assemble();
        bicycle.wash();
        return bicycle;
    }
};

這個BicycleFactory對象可以供各種類用來創(chuàng)建新的自行車實(shí)例。有關(guān)可供車型的所有信息集中在一個地方管理 ,所以添加更多車型很容易:

/* BicycleFactory namespace,with more models. */
var BicycleFactory = {
    createBicycle: function (model) {
        var bicycle;
        switch (model) {
            case "The Speedster":
                bicycle = new SpeedSter();
                break;
            case "The Lowrider":
                bicycle = new Lowrider();
                break;
            case "The Flatlander":
                bicycle = new Flatlander();
                break;
            case "The Comfort Cruiser":
            default:
                bicycle = new ComfortCruiser();
        }
        Interface.ensureImplements(bicycle, Bicycle);
        return bicycle;
    }
};
15.工廠模式
真正的工廠模式與簡單工廠模式的區(qū)別在于,它不是另外使用一個類或?qū)ο髞韯?chuàng)建自行車,而是使用一個子類。按照正式定義,工廠是一個將其成員對象的實(shí)例化推遲到子類中進(jìn)行的類。
16.工廠模式的適用場合

動態(tài)實(shí)現(xiàn):如果需要創(chuàng)建一些用不同方式實(shí)現(xiàn)同一接口的對象,那么可以使用一個工廠方法或簡單工廠對象來簡化選擇實(shí)現(xiàn)的過程。

節(jié)省設(shè)置開銷:如果對象需要進(jìn)行復(fù)雜并且彼此相關(guān)的設(shè)置,那么使用工廠模式可以減少每種對象所需的代碼量。如果這種設(shè)置只需要為特定類型的所有實(shí)例執(zhí)行一次即可,這種作用尤為突出。把這種設(shè)置代碼放到類的構(gòu)造函數(shù)中并不是一種高效的做法,這是因為即便設(shè)置工作已經(jīng)完成,每次創(chuàng)建新實(shí)例的時候這些代碼還是會執(zhí)行,而且這樣做會把設(shè)置代碼分散到不同的類中。工廠方法非常適合于這種場合。它可以在實(shí)例化所有需要的對象之前先一次性地進(jìn)行設(shè)置。無論有多少類會被實(shí)例化,這種辦法都可以讓設(shè)置代碼集中在一個地方。

用許多小型對象組成一個大對象

17.工廠模式之利

工廠模式的主要好處在于消除對象間的耦合。通過使用工廠方法而不是new關(guān)鍵字及具體類,你可以把所有實(shí)例化的代碼集中在一個位置。這可以大大簡化更換所用的類或在運(yùn)行期間動態(tài)選擇所用的類的工作。在派生子類時它也提供了更強(qiáng)大的靈活性。

所有這些好處都與面向?qū)ο笤O(shè)計的這兩條原則有關(guān):弱化對象間的耦合;防止代碼的重復(fù)。在一個方法中進(jìn)行類的實(shí)例化,可以消除重復(fù)性的代碼。這是在用一個對接口的調(diào)用取代一個具體的實(shí)現(xiàn)。這些都有助于創(chuàng)建模塊化的代碼。

18.橋接模式

橋接模式最常見和實(shí)際的應(yīng)用場合之一就是事件監(jiān)聽器回調(diào)函數(shù)。假設(shè)有一個名為getBeerById的API函數(shù),它根據(jù)一個標(biāo)識符返回有關(guān)某種啤酒的信息。你希望用戶在點(diǎn)擊的時候獲取這種信息。那個被點(diǎn)擊的元素很可能有啤酒的標(biāo)識符信息,它可能是作為元素自身的ID保存,也可能是作為別的自定義屬性保存。下面是一種做法:

addEvent(element, "click", getBeerById);
function getBeerById(e) {
    var id = this.id;
    asyncRequest("GET", "beer.uri?id=" + id, function (resp) {
        console.log(resp.responseText);
    });
}

這個API只能工作在瀏覽器中,如果要對這個API函數(shù)做單元測試,或者在命令行中執(zhí)行,可能會報錯。一個優(yōu)良的API設(shè)計,不應(yīng)該把它與任何特定的實(shí)現(xiàn)攪在一起。

function getBeerById(id, callback) {
    asyncRequest("GET", "beer.uri?id=" + id, function (resp) {
        callback(resp.responseText);
    })
}

現(xiàn)在我們將針對接口而不是實(shí)現(xiàn)進(jìn)行編程,用橋接模式把抽象隔離開來:

addEvent(element, "click", getBeerByIdBridge);
function getBeerBIdBridge(e) {
    getBeerById(this.id, function (beer) {
        console.log(beer);
    });
}

這下getBeerById并沒有和事件對象捆綁在一起了。

19.用橋接模式聯(lián)結(jié)多個類
var Class1 = function (a, b, c) {
    this.a = a;
    this.b = b;
    this.c = c;
};
var Class2 = function (d) {
    this.d = d;
};
var BridgeClass = function (a, b, c, d) {
    this.one = new Class1(a, b, c);
    this.two = new Class2(d);
};
20.適配器模式

適配器模式可以用來在現(xiàn)有接口和不兼容的類之間進(jìn)行適配。使用這種模式的對象又叫包裝器,因為它們是在用一個新的接口包裝另一個對象。

21.適配器的特點(diǎn)

適配器可以被添加到現(xiàn)有代碼中以協(xié)調(diào)兩個不同的接口。如果現(xiàn)有代碼的接口能很好地滿足需要,那就可能沒有必要使用適配器。

從表面上看,適配器模式很像門面模式。它們都要對別的對象進(jìn)行包裝并改變其呈現(xiàn)的接口。二者的差別在于它們?nèi)绾胃淖兘涌凇iT面元素展現(xiàn)的是一個簡化的接口,它并不提供額外的選擇,而且有時為了方便完成某些常見任務(wù)它還會做出一些假定。而適配器則要把一個接口轉(zhuǎn)換為另一個接口,它并不會濾除某些能力,也不會簡化接口。如果客戶系統(tǒng)期待的API不可用,那就需要用到適配器。

適配器可被實(shí)現(xiàn)為不兼容的方法調(diào)用之間的一個代碼薄層。

示例:

假如你有一個對象還有一個以三個字符串為參數(shù)的函數(shù):

    var clientObject = {
        string1: "foo",
        string2: "bar",
        string3: "baz"
    };
    function interfaceMethod(str1, str2, str3) {

    }

為了把clientObject作為參數(shù)傳遞給interfaceMethod,需要用到適配器。我們可以這樣創(chuàng)建一個:

function clientToInterfaceAdapter(o) {
    interfaceMethod(o.string1, o.string2, o.string3);
}
//現(xiàn)在就可以把整個對象傳給這個函數(shù)
clientToInterfaceAdapter(clientObject);

clientToInterfaceAdapter函數(shù)的作用就在于對interfaceMethod函數(shù)進(jìn)行包裝,并把傳遞給它的參數(shù)轉(zhuǎn)換給后者需要的形式。

22.裝飾者模式
裝飾者模式可用來透明地把對象包裝在具有同樣接口的另一對象中。這樣一來,你可以給一個方法添加一些行為,然后將方法調(diào)用傳遞給原始對象。相對于創(chuàng)建子類來說,使用裝飾者對象是一種更靈活的選擇。
23.享元模式
享元模式最適合于解決因創(chuàng)建大量類似對象而累及的性能問題。這種模式在JavaScript中尤其有用,因為復(fù)雜的JavaScript代碼可能很快就會用光瀏覽器的所有可用內(nèi)存。通過把大量獨(dú)立對象轉(zhuǎn)化為少量共享對象,可以降低運(yùn)行Web應(yīng)用程序所需的資源數(shù)量。

享元模式用于減少應(yīng)用程序所需對象的數(shù)量。這是通過將對象的內(nèi)部狀態(tài)劃分為內(nèi)在數(shù)據(jù)和外在數(shù)據(jù)兩類而實(shí)現(xiàn)的。內(nèi)在數(shù)據(jù)是指類的內(nèi)部方法所需的信息,沒有這種數(shù)據(jù)的話類不能正常運(yùn)轉(zhuǎn)。外在數(shù)據(jù)則是可以從類身上剝離并存儲在其外部的信息。我們可以將內(nèi)在狀態(tài)相同的所有對象替換為同一個共享對象,這種方法可以把對象數(shù)量減少到不同內(nèi)在狀態(tài)的數(shù)量。

24.實(shí)現(xiàn)享元模式的一般步驟

將所有外在數(shù)據(jù)從目標(biāo)剝離。具體做法是盡可能多地刪除該類的屬性,所刪除的應(yīng)該是那種因?qū)嵗惖膶傩浴?gòu)造函數(shù)的參數(shù)也要這樣處理。這些參數(shù)應(yīng)該被添加到該類的各個方法。這些外在數(shù)據(jù)現(xiàn)在不再保存在類的內(nèi)部,而是由管理器提供給類的方法。經(jīng)過這樣的處理后,目標(biāo)類應(yīng)該依然具有與之前一樣的功能。唯一的區(qū)別在于數(shù)據(jù)的來源發(fā)生了變化。

創(chuàng)建一個用來控制該類的實(shí)例化的工廠。這個工廠應(yīng)該掌握該類所有已創(chuàng)建出來的獨(dú)一無二的實(shí)例。其具體做法之一是用一個對象字面量來保存每一個這類對象的引用,并以用來生成這些對象的參數(shù)的唯一性組合作為它們的索引。這樣一來,每次要求工廠提供一個對象時,它會先檢查那個對象字面量,看看以前是否請求過這個對象。如果是,那么只要返回那個現(xiàn)有對象的引用就行。否則它會創(chuàng)建一個新對象并將其引用保存在那個對象字面量中,然后返回這個對象。另一種做法稱為對象池,這種技術(shù)用數(shù)組來保存所創(chuàng)建的對象的引用。它適合于注重可用對象的數(shù)量而不是那些多帶帶配置的實(shí)例的場合。這種技術(shù)可用來將所實(shí)例化的對象的數(shù)目維持在最低值。工廠會處理根據(jù)內(nèi)在數(shù)據(jù)創(chuàng)建對象的所有事宜。

創(chuàng)建一個用來保存外在數(shù)據(jù)的管理器。該管理器對象負(fù)責(zé)控制處理外在數(shù)據(jù)的種種事宜。在實(shí)施優(yōu)化之前,要是需要一個目標(biāo)類的實(shí)例,你會把所有數(shù)據(jù)傳給構(gòu)造函數(shù)以創(chuàng)建其新實(shí)例。而現(xiàn)在要是需要一個實(shí)例,你會調(diào)用管理器的某個方法,把所有數(shù)據(jù)都提供給它。這個方法會分辨內(nèi)在數(shù)據(jù)和外在數(shù)據(jù)。它把內(nèi)在數(shù)據(jù)提供給工廠對象以創(chuàng)建一個對象(或者,如果已經(jīng)存在這樣一個對象的話,則重用該對象)。外在數(shù)據(jù)則被保存在管理器內(nèi)的一個數(shù)據(jù)結(jié)構(gòu)中。管理器隨后會根據(jù)需要將這些數(shù)據(jù)提供給共享對象的方法,其效果就如同該類有許多實(shí)例一樣。

25.觀察者模式

在事件驅(qū)動的環(huán)境中,比如瀏覽器這種持續(xù)尋求用戶關(guān)注的環(huán)境中,觀察者模式(又名發(fā)布者-訂閱者模式)是一種管理人與其任務(wù)之間的關(guān)系(確切的說,是對象及其行為和狀態(tài)之間的關(guān)系)的得力工具。

觀察者模式中存在兩個角色:觀察者和被觀察者。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/79986.html

相關(guān)文章

  • JS程序

    摘要:設(shè)計模式是以面向?qū)ο缶幊虨榛A(chǔ)的,的面向?qū)ο缶幊毯蛡鹘y(tǒng)的的面向?qū)ο缶幊逃行┎顒e,這讓我一開始接觸的時候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續(xù)了解設(shè)計模式必須要先搞懂面向?qū)ο缶幊蹋駝t只會讓你自己更痛苦。 JavaScript 中的構(gòu)造函數(shù) 學(xué)習(xí)總結(jié)。知識只有分享才有存在的意義。 是時候替換你的 for 循環(huán)大法了~ 《小分享》JavaScript中數(shù)組的那些迭代方法~ ...

    melody_lql 評論0 收藏0
  • 2017年 最好的javascript 書籍

    摘要:請記住,這些書中的一些可能不是最新的,但概念和基礎(chǔ)仍應(yīng)適用。是最好的老師之一。的秘密由部分組成。在你完成這些書后,查看書籍和最好的本土?xí)? 我看過三本,第1本,第二本,第四本。第一本買的的實(shí)體書,其他兩本看的是電子書。第一本是大名鼎鼎老道寫的,書很薄,但是非常經(jīng)典。javascirpt忍者秘籍是jquery的作者寫的,也是非常經(jīng)典。you dont kown js系列也是非常好。看了...

    mingzhong 評論0 收藏0
  • 前端練級攻略(第二部分)

    摘要:是文檔的一種表示結(jié)構(gòu)。這些任務(wù)大部分都是基于它。這個實(shí)踐的重點(diǎn)是把你在前端練級攻略第部分中學(xué)到的一些東西和結(jié)合起來。一旦你進(jìn)入框架部分,你將更好地理解并使用它們。到目前為止,你一直在使用進(jìn)行操作。它是在前端系統(tǒng)像今天這樣復(fù)雜之前編寫的。 本文是 前端練級攻略 第二部分,第一部分請看下面: 前端練級攻略(第一部分) 在第二部分,我們將重點(diǎn)學(xué)習(xí) JavaScript 作為一種獨(dú)立的語言,如...

    BWrong 評論0 收藏0
  • 理解JavaScript的核心知識點(diǎn):原型

    摘要:首先,需要來理清一些基礎(chǔ)的計算機(jī)編程概念編程哲學(xué)與設(shè)計模式計算機(jī)編程理念源自于對現(xiàn)實(shí)抽象的哲學(xué)思考,面向?qū)ο缶幊淌瞧湟环N思維方式,與它并駕齊驅(qū)的是另外兩種思路過程式和函數(shù)式編程。 JavaScript 中的原型機(jī)制一直以來都被眾多開發(fā)者(包括本人)低估甚至忽視了,這是因為絕大多數(shù)人沒有想要深刻理解這個機(jī)制的內(nèi)涵,以及越來越多的開發(fā)者缺乏計算機(jī)編程相關(guān)的基礎(chǔ)知識。對于這樣的開發(fā)者來說 J...

    iKcamp 評論0 收藏0
  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函數(shù)式編程前端掘金引言面向?qū)ο缶幊桃恢币詠矶际侵械闹鲗?dǎo)范式。函數(shù)式編程是一種強(qiáng)調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。 JavaScript 函數(shù)式編程 - 前端 - 掘金引言 面向?qū)ο缶幊桃恢币詠矶际荍avaScript中的主導(dǎo)范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數(shù)式編程越來越多得受到開發(fā)者的青睞。函數(shù)式編程是一種強(qiáng)調(diào)減少對程序外部狀態(tài)產(chǎn)生改變的方式。因此,...

    cfanr 評論0 收藏0
  • JavaScript進(jìn)階之路

    摘要:前端入門的門檻相對較低,學(xué)習(xí)曲線是越來越陡峭,由淺入深,可以分為四個階段。第二階段高級程序設(shè)計有的書是用來成為經(jīng)典的,比如犀牛書還有些書是用來超越經(jīng)典的,顯然這本書就是。接下來可以看看教程,看看源代碼,嘗試著寫一寫這些效果。 前端入門的門檻相對較低,學(xué)習(xí)曲線是越來越陡峭,由淺入深,可以分為四個階段。 第一階段:《JavaScript DOM編程藝術(shù)》    看這本書之前,請先確認(rèn)你對J...

    Lowky 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<