JavaScript設計模式系列二之建造者模式(附案例原始碼)

小錢錢阿聖發表於2019-02-04

文章初衷

設計模式其實旨在解決語言本身存在的缺陷,

目前javaScript一些新的語法特性已經整合了一些設計模式的實現,

大家在寫程式碼的時候,沒必要為了用設計模式而去用設計模式,

那麼我這邊為什麼還寫設計模式的文章呢,

一方面是自己的一個整理,然後記錄出來,結合自己的理解,

一方面就是雖然語言特性本身已經實現這些模式,有了自己的語法,

但是我們何嘗不能去了解一下它是通過什麼樣的思路去實現了

在我看來設計模式更多的是讓我對於思考問題,有了一些更好的思路和想法

文章實現更多的表現為用一些簡單的案例,幫助大家去理解這樣的一種思路,

會存在故意把設計模式的實現往簡單的案例靠攏,

大家在真實專案中不要刻意去用設計模式實現相同的程式碼

設計模式在平時的一些程式碼中都會有所體現,大家也許經常用到,

耐心看文章,也許你會發現自己平時的程式碼就不斷在設計模式中體現

JavaScript設計模式系列

JavaScript設計模式系列,講述大概20-30種設計模式在JavaScript中的運用

後面對應的篇幅會陸續更新,歡迎大家提出建議

這是設計模式系列第二篇,講述建造者模式

上篇文章講述了工廠設計模式,有興趣可以檢視

注意

JavaScript設計模式系列github地址

深入系列文章部分是有先後順序的,按照目錄結構順序閱讀效果最好。

勘誤及提問

如果有疑問或者發現錯誤,可以在相應的 issues 進行提問或勘誤。

如果喜歡或者有所啟發,歡迎 star,對作者也是一種鼓勵。

建造者模式

概念:

將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立

不同的表示。

不管扯淡的概念,上?,後面再反過頭來理解這句話

// #建造者模式 


// 抽象建造者
var Car = function (param) {
    // 速度
    this.speed = param && param.speed || `0`;
    // 重量
    this.weight = param && param.weight || `0`;
}


Car.prototype = {
    // 獲取速度
    getSpeed: function () {
        return this.speed;
    },
    // 獲取重量
    getWeight: function () {
        return this.weight
    }
}

// 輪胎部件類
var Tyre = function (type) {
    var that = this;
    // 構造器
    // 建構函式中通過傳入的type型別設定相對應的輪胎尺寸
    (function (type,that) {
        switch (type) {
            case `small`:
            that.tyre = `小號輪胎`;
            that.tyreIntro = `正在使用小號輪胎`;
            break;
            case `normal`:
            that.tyre = `中號輪胎`;
            that.tyreIntro = `正在使用中號輪胎`;
            break;
            case `big`:
            that.tyre = `大號輪胎`;
            that.tyreIntro = `正在使用大號輪胎`;
            break;
        }
    })(type,this);
}


Tyre.prototype = {
    // 更換輪胎的方法
    changeType: function (type) {
        that.tyre = type;
        that.tyreIntro = `正在使用`+type;
    }
}


// 發動機部件類
var Engine = function (type) {
    var that = this;
    // 構造器
    // 建構函式中通過傳入的type型別設定相對應的發動機型別
    (function (type,that) {
        switch (type) {
            case `small`:
            that.engine = `小號發動機`;
            that.engineIntro = `正在使用小號發動機`;
            break;
            case `normal`:
            that.engine = `中號發動機`;
            that.engineIntro = `正在使用中號發動機`;
            break;
            case `big`:
            that.engine = `大號發動機`;
            that.engineIntro = `正在使用大號發動機`;
            break;
        }
    })(type,this);
}


Engine.prototype = {
    // 更換髮動機的方法
    changeType: function (type) {
        that.engine = type;
        that.engineIntro = `正在使用`+type;
    }
}

/**
 * 指揮者,建造一個賓士車的類
 * @param {*輪胎型別 small normal big} tyre 
 * @param {*發動機型別 small normal big} engine 
 * @param {*車輛基本屬性 param.speed:速度 param.weight: 重量} param 
 */
var BenChi = function (tyre,engine,param) {
    // 建立一個車輛快取物件
    var _car = new Car(param);
    // 建立車輛的輪胎
    _car.tyreInfo = new Tyre(tyre);
    // 建立車輛的發動機
    _car.engineInfo = new Engine(engine);
    // 將建立的車輛物件返回
    return _car;
}

// 具體建造者 例項化賓士車類
var benchi1 = new BenChi(`small`,`big`,{speed: 200,weight: `200`});
console.log(benchi1.speed);// 200
console.log(benchi1.weight);// 200
console.log(benchi1.tyreInfo.tyre);// 小號輪胎
console.log(benchi1.tyreInfo.tyreIntro);// 正在使用小號輪胎
console.log(benchi1.engineInfo.engine);// 大號發動機
console.log(benchi1.engineInfo.engineIntro);// 正在使用大號發動機

// #建造者模式end複製程式碼

這段例子是這樣的意思,首先我們要建造一個車,

那麼車是一個比較複雜的東西,我們需要輪胎部件,發動機部件等等其他

複雜的部件,每個部件相對來說又是獨立的個體,又是具備很多獨立的行為

那麼針對這種複雜的物件(例子中是一輛車),我們把它分成一個個部件,

然後通過一系類的組裝,把這些部件都拼接在一起,組成一個複雜的物件,

這樣的方式就是建造者模式,一步步構建一個複雜的物件,

使用者只關心最後建造出來的車,不需要關心它具體的部件是如何實現的

建造者模式中存在的角色

這邊介紹一下建造者模式中存在的角色,方便大家去理解

  • 抽象建造者
  • 指揮者
  • 具體建造者

結合上面的案例,我們去把案例中的情況根據角色去劃分一下,

這樣更好的去理解建造者模式

首先Car就是抽象建造者,它具備一些車的基本屬性還有方法,

它是抽象的,使用者不需要知道它的存在,

那麼Tyre(輪胎),Engine(發動機),分別就是車的具體部件(具體類),

建立的BenChi類,其實就是一個指揮者的角色,負責把對應的部件組裝起來,

具體建立一個什麼樣子的車,就是指揮者這邊決定的,

比如說這邊還有一個空調部件,有些車沒有的話,那麼指揮者在建立的時候,

就不需要加入這個部件,所以物件的建造都是指揮者這邊決定的

再下面就是具體建造者了,指揮者建立了一個賓士車的類,

那麼具體建造者,通過呼叫這個類去實現不同的車系,

比如賓士車它有很多系列,通過傳遞不同的引數,就可以建立不同的系列

這就是一個完整的建造者案例,把複雜物件簡單化,通過建造不同的部件類,

組成一個複雜的物件,不同的部件,在建立不同物件的時候,可以進行復用。

建造者模式的優點

  • 在建造者模式中,客戶端不必知道產品內部組成的細節,將產品本身與產品的建立過程解耦,使得相同的建立過程可以建立不同的產品物件

  • 每一個具體建造者都相對獨立,而與其他的具體建造者無關,因此可以很方便地替換具體建造者或增加新的具體建造者,使用者使用不同的具體建造者即可得到不同的產品物件

  • 可以更加精細地控制產品的建立過程。將複雜產品的建立步驟分解在不同的方法中,使得建立過程更加清晰,也更方便使用程式來控制建立過程。

  • 增加新的具體建造者無須修改原有類庫的程式碼,指揮者類針對抽象建造者類程式設計,系統擴充套件方便,符合“開閉原則”

建造者模式的缺點

  • 建造者模式所建立的產品一般具有較多的共同點,其組成部分相似,如果產品之間的差異性很大,則不適合使用建造者模式,因此其使用範圍受到一定的限制。
  • 如果產品的內部變化複雜,可能會導致需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大。

建造者模式的適用情況

  • 需要生成的產品物件有複雜的內部結構,這些產品物件通常包含多個成員屬性。

  • 隔離複雜物件的建立和使用,並使得相同的建立過程可以建立
    不同的產品。

工廠模式與建造者模式的比較

相關工廠模式的內容,可以檢視工廠設計模式

  • 與抽象工廠模式相比,建造者模式返回一個組裝好的完整產品,
    而抽象工廠模式返回一系列相關的產品
    ,這些產品位於不同的產品等級結構,構成了一個產品族。
  • 在抽象工廠模式中,客戶端例項化工廠類,然後呼叫工廠方法獲取所需產品物件,而在建造者模式中,客戶端可以不直接呼叫建造者的相關方法,而是通過指揮者類來指導如何生成物件,包括物件的組裝過程和建造步驟,
    它側重於一步步構造一個複雜物件,返回一個完整的物件
  • 如果將抽象工廠模式看成汽車配件生產工廠,生產一個產品族的產品,
    那麼建造者模式就是一個汽車組裝工廠,通過對部件的組裝可以返回一輛完整的汽車。

建造者模式的總結

  • 建造者模式將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。建造者模式是一步一步建立一個複雜的物件,它允許使用者只通過指定複雜物件的型別和內容就可以構建它們,使用者不需要知道內部的具體構建細節。建造者模式屬於物件建立型模式。

  • 建造者模式包含3個角色,抽象建造者建立物件的基本屬性方法,
    指揮者用來組裝具體的部件,形成不同的物件,具體建造者負責實現指揮者建立的物件

最後我們再來理解建造者模式的概念就比較簡單了:

將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立

不同的表示。

注意

JavaScript設計模式系列github地址

深入系列文章部分是有先後順序的,按照目錄結構順序閱讀效果最好。

關於設計模式,更多的是結合我自己的一些理解,把他總結出來分享給大家,如果大家發現有什麼不正確的地方,希望大家一定得提出來,避免我這邊誤人子弟,感謝大家!!!

相關文章