JavaScript工廠模式

JavaScript工廠模式

首先須要說一下工廠模式。工廠模式根據抽象程度的不一樣分爲三種數據庫

  • 簡單工廠模式
  • 工廠方法模式
  • 抽象工廠模式

1.簡單工廠模式

簡單工廠模式:又稱爲靜態工廠方法模式,它屬於類建立型模式。
在簡單工廠模式中,能夠根據參數的不一樣返回不一樣類的實例。
由工廠對象決定建立某一種產品對象類的實例。緩存

// #簡單工廠模式第一種
/**
 * 足球類
 */
var FootBall = function  () {
    this.play = function () {
        console.log('我在踢足球');
    }
}

/**
 * 籃球類
 */
var BasketBall = function  () {
    this.play = function () {
        console.log('我在打籃球');
    }
}

var football = new FootBall();
football.play();
var basketball = new BasketBall();
basketball.play();

/**
 * 球類工廠
 */
var Ball = function(name) {
    switch (name) {
        case '足球':
            return new FootBall();
        break;
        case '籃球':
            return new BasketBall();
        break;
    }
}
var football =  Ball('足球');
football.play();
var basketball =  Ball('籃球');
basketball.play();

// #簡單工廠模式第一種end

這段案例能夠簡單的這麼去理解,假設咱們須要多個球,咱們但願在使用球的時候,只須要告訴管理員咱們須要的球的類型,不須要一個個去找對應的球這個管理員就相對於工廠函數。安全

簡單講就是使用簡單工廠模式,那麼你就不須要關心它的具體實現,你只須要知道你要使用的類型,那麼工廠函數會自動幫你去作對應的事情函數

// #簡單工廠模式第二種

/**
 * 球類工廠
 */
var Ball = function(name) {
    // 建立一個對象,對對象擴展擴展屬性還有方法
    var o = new Object();
    o.name = name;
    //默認的方法 若是在加上一個羽毛球類,這時候就不須要補充play方法
    o.play = function () {
        console.log('我在打'+name);
    }
    if (name === '足球') {
        o.play = function () {
            console.log('我在踢'+name);
        }
    }else if (name === '籃球') {
        o.play = function () {
            console.log('我在打'+name);
        }
    }
    // 將對象返回
    return o;
}
var football =  Ball('足球');
football.play();
var basketball =  Ball('籃球');
basketball.play();

// #簡單工廠模式第二種end

這段案例是用對象的方式代替多個類,把相同點抽離出來,this

不一樣點在一一作類型判斷,這樣也是簡單工廠模式實現的另外一種方式prototype

簡單工廠模式的優勢:設計

  • 工廠類含有必要的判斷邏輯,能夠決定在何時建立哪個產品類的實例,客戶端能夠免除直接建立產品對象的責任,而僅僅「消費」產品;簡單工廠模式經過這種作法實現了對責任的分割,它提供了專門的工廠類用於建立對象
  • 客戶端無須知道所建立的具體產品類的類名,只須要知道具體產品類所對應的參數便可,對於一些複雜的類名,經過簡單工廠模式能夠減小使用者的記憶量。

簡單工廠模式的缺點code

  • 因爲工廠類集中了全部產品建立邏輯,一旦不能正常工做,整個系統都要受到影響。
  • 使用簡單工廠模式將會增長系統中類的個數,在必定程序上增長了系統的複雜度和理解難度。
  • 系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能形成工廠邏輯過於複雜,不利於系統的擴展和維護。

簡單工廠模式的適用狀況對象

在如下狀況下可使用簡單工廠模式:繼承

  • 工廠類負責建立的對象比較少:因爲建立的對象較少,不會形成工廠方法中的業務邏輯太過複雜。
  • 客戶端只知道傳入工廠類的參數,對於如何建立對象不關心:客戶端既不須要關心建立細節,甚至連類名都不須要記住,只須要知道類型所對應的參數。

簡單工廠模式總結

  • 簡單工廠模式的要點在於:當你須要什麼,只須要傳入一個正確的參數,就能夠獲取你所須要的對象,而無須知道其建立細節。
  • 簡單工廠模式最大的優勢在於實現對象的建立和對象的使用分離,將對象的建立交給專門的工廠類負責,可是其最大的缺點在於工廠類不夠靈活,增長新的具體產品須要修改工廠類的判斷邏輯代碼,並且產品較多時,工廠方法代碼將會很是複雜。

2.工廠方法模式

工廠方法模式:又稱爲工廠模式,也叫虛擬構造器模式或者多態工廠模式它屬於類建立型模式。在工廠方法模式中,工廠父類負責定義建立產品對象的公共接口,而工廠子類則負責生成具體的產品對象,這樣作的目的是將產品類的實例化操做延遲到工廠子類中完成,即經過工廠子類來肯定究竟應該實例化哪個具體產品類這樣解釋可能會有點抽象。

// # 工廠方法模式
// 安全模式建立工廠類
var Ball = function (type,name) {
    /**
     * 安全模式 Ball也能夠運行處new Ball的效果
     */
    if(this instanceof Ball) {
        var s = new this[type](name);
        return s;
    }else {
        return new Ball(type,name);
    }
}
// 工廠原型中設置建立全部類型數據對象的基類
Ball.prototype = {
    basketBall: function(name) {
        this.play = function() {
            console.log('我在打'+name);
        }
    },
    footBall: function(name) {
        this.play = function() {
            console.log('我在踢'+name);
        }
    },
    badmintonBall: function(name) {
        this.play = function() {
            console.log('我在打'+name);
        }
    },
    // ....
}
var football = new Ball('footBall','足球');
football.play();
var basketball = new Ball('basketBall','籃球');
basketball.play();
var badmintonball = new Ball('badmintonBall','羽毛球');
badmintonball.play();

// # 工廠方法模式end

這段案例是這麼去理解的,咱們先建立一個球類工廠,這個球類工廠是一個抽象的,不作具體的實現,而後咱們在這個球類工廠裏面在去定義對應的球類實現,如籃球,羽毛球,足球等實現,在工廠方法模式中,抽象類工廠只是負責定義一個對外的公共接口,而工廠子類則負責生成具體的產品對象。

這樣作的目的是將產品類的實例化操做延遲到工廠子類中完成,即經過工廠子類來肯定究竟應該實例化哪個具體產品類若是這時候在出現一個新的球類運動,只須要爲這種新類型的球類建立一個具體的球類實現就能夠,這一特色無疑使得工廠方法模式具備超越簡單工廠模式的優越性,更加符合「開閉原則」

上面案例包含了一個安全模式的知識點

// 安全模式建立工廠類
var Ball = function (type,name) {
    /**
     * 安全模式 Ball也能夠運行處new Ball的效果
     */
    if(this instanceof Ball) {
        var s = new this[type](name);
        return s;
    }else {
        return new Ball(type,name);
    }
}

這段代碼主要解決的問題是,有些同窗使用工廠類的時候,忘記使用關鍵字new,得不到預期想要的效果這邊的解決方案就是,在構造函數開始時先判斷當前對象this指代是否是當前工廠類,若是不是則經過new關鍵字建立對象返回,這樣就能夠實現不使用new關鍵詞也能夠達到相同的效果了

工廠方法模式的優勢:

  • 在工廠方法模式中,工廠方法用來建立客戶所須要的產品,同時還向客戶隱藏了哪一種具體產品類將被實例化這一細節,用戶只須要關心所需產品對應的工廠,無須關心建立細節,甚至無須知道具體產品類的類名。
  • 基於工廠角色和產品角色的多態性設計是工廠方法模式的關鍵。它可以使工廠能夠自主肯定建立何種產品對象,而如何建立這個對象的細節則徹底封裝在具體工廠內部。工廠方法模式之因此又被稱爲多態工廠模式,是由於全部的具體工廠類都具備同一抽象父類。
  • 使用工廠方法模式的另外一個優勢是在系統中加入新產品時,無須修改抽象工廠和抽象產品提供的接口,無須修改客戶端,也無須修改其餘的具體工廠和具體產品,而只要添加一個具體工廠和具體產品就能夠了。這樣,系統的可擴展性也就變得很是好,徹底符合「開閉原則」。

工廠方法模式的缺點:

  • 在添加新產品時,須要編寫新的具體產品類,並且還要提供與之對應的具體工廠類,系統中類的個數將成對增長,在必定程度上增長了系統的複雜度,有更多的類須要編譯和運行,會給系統帶來一些額外的開銷。
  • 因爲考慮到系統的可擴展性,須要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增長了系統的抽象性和理解難度

工廠方法模式的適用狀況

在如下狀況下可使用工廠方法模式:

  • 一個類不知道它所須要的對象的類:在工廠方法模式中,客戶端不須要知道具體產品類的類名,只須要知道所對應的工廠便可,具體的產品對象由具體工廠類建立;客戶端須要知道建立具體產品的工廠類。
  • 一個類經過其子類來指定建立哪一個對象:在工廠方法模式中,對於抽象工廠類只須要提供一個建立產品的接口,而由其子類來肯定具體要建立的對象,利用面向對象的多態性和里氏代換原則,在程序運行時,子類對象將覆蓋父類對象,從而使得系統更容易擴展。
  • 將建立對象的任務委託給多個工廠子類中的某一個,客戶端在使用時能夠無須關心是哪個工廠子類建立產品子類,須要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。

工廠方法模式總結

工廠方法模式是簡單工廠模式的進一步抽象和推廣。因爲使用了面向對象的多態性,工廠方法模式保持了簡單工廠模式的優勢,並且克服了它的缺點。在工廠方法模式中,核心的工廠類再也不負責全部產品的建立,而是將具體建立工做交給子類去作。這個核心類僅僅負責給出具體工廠必須實現的接口,而不負責產品類被實例化這種細節,這使得工廠方法模式能夠容許系統在不修改工廠角色的狀況下引進新產品。
工廠方法模式的主要優勢是增長新的產品類時無須修改現有系統,並封裝了產品對象的建立細節,系統具備良好的靈活性和可擴展性;其缺點在於增長新產品的同時須要增長新的工廠,致使系統類的個數成對增長,在必定程度上增長了系統的複雜性。

3.抽象工廠模式

抽象工廠模式:經過對類的工廠抽象使其業務用於對產品類簇的建立,而不是負責建立某一類產品的實例,屬於對象建立型模式。

抽象類一直出如今咱們的文章中,那麼這邊先來解釋一下什麼是抽象類

抽象類是一種聲明但不能使用的類,當你使用時就會報錯,在JavaScript中abstract仍是一個保留字,因此目前來講還不能像
傳統面嚮對象語言那麼輕鬆的去建立抽象類.

不過JavaScript有本身的實現方式,能夠模擬出抽象類

來一段代碼

// 抽象類的介紹
var Ball = function () {}
Ball.prototype = {
    play: function () {
        return new Error('抽象方法不能調用');
    }
}

解釋:

咱們能夠看到建立的Ball類其實什麼都不能作,建立時沒有任何屬性,原型定義的方法也不能使用,不然就會報錯。可是在繼承上倒是頗有用的,
由於定義了一種類,並定義了該類所具有的方法,若是沒有在子類中重寫這寫方法,那麼調用的時候就會報錯。

這一特色能夠很好的提醒子類去重寫這一方法,否則會在調用的時候提示錯誤那麼在瞭解了什麼是抽象類的狀況下,咱們在來比較一下工廠方法模式與抽象工廠模式的不一樣點,以方便咱們更好的去理解抽象工廠模式

工廠方法模式與抽象工廠模式的對比

在工廠方法模式中具體工廠負責生產具體的產品,每個具體工廠對應一種具體產品,工廠方法也具備惟一性,通常狀況下,一個具體工廠中只有一個工廠方法或者一組重載的工廠方法。可是有時候咱們須要一個工廠能夠提供多個產品對象,而不是單一的產品對象。

爲了更清晰地理解抽象工廠模式,須要先引入兩個概念:

  • 產品等級結構 :產品等級結構即產品的繼承結構,如一個抽象類是電視機,其子類有海爾電視機、海信電視機、TCL電視機,則抽象電視機與具體品牌的電視機之間構成了一個產品等級結構,抽象電視機是父類,而具體品牌的電視機是其子類。
  • 產品族 :在抽象工廠模式中,產品族是指由同一個工廠生產的,位於不一樣產品等級結構中的一組產品,如海爾電器工廠生產的

海爾電視機、海爾電冰箱,海爾電視機位於電視機產品等級結構中,海爾電冰箱位於電冰箱產品等級結構中。

抽象工廠模式與工廠方法模式最大的區別在於,工廠方法模式針對的是一個產品等級結構,而抽象工廠模式則須要面對多個產品等級結構,一個工廠等級結構能夠負責多個不一樣產品等級結構中的產品對象的建立。當一個工廠等級結構能夠建立出分屬於不一樣產品等級結構的一個產品族中的全部對象時,抽象工廠模式比工廠方法模式更爲簡單、有效率。

這句話比較簡單的理解方式就是:若是一個工廠只須要生產一個類型的產品好比說電視機,那麼用工廠方法模式是比較合理的,若是這個工廠又須要成產電視機,又須要生產冰箱之類的,那麼這時候用工廠抽象模式就是最合適的。

// # 抽象工廠模式
var Sport = function(subType, superType) {
    if( typeof Sport[superType] === 'function'){
        // 緩存類
        function F() {};
        // 繼承父類屬性和方法
        F.prototype = new Sport[superType]();
        // 將子類constructor 指向子類
        subType.constructor = subType;
        // 子類原型繼承 「父類」
        subType.prototype = new F(); 
    }else {
        // 不存在抽象類則拋出錯誤
        throw new Error('未建立該抽象類');
    }
}

// 球類運動抽象類
Sport.Ball = function () {
    this.type = 'ball';
}
Sport.Ball.prototype = {
    play: function () {
        return new Error('抽象方法不能調用');
    }
}

// 力量型運動抽象類
Sport.Power = function () {
    this.type = 'power';
}
Sport.Power.prototype = {
    play: function () {
        return new Error('抽象方法不能調用');
    }
}

// 速度型運動抽象類
Sport.Speed = function () {
    this.type = 'speed';
}
Sport.Speed.prototype = {
    play: function () {
        return new Error('抽象方法不能調用');
    }
}

// 籃球類
var BasketBall = function (name) {
    this.name = name;
};
// 抽象工廠實現對球類運動的繼承
Sport(BasketBall,'Ball');
BasketBall.prototype.play = function () {
    console.log('我在玩'+this.name);
}


// 舉重類
var WeightLifting = function (name) {
    this.name = name;
};
// 抽象工廠實現對力量型運動的繼承
Sport(WeightLifting,'Power');
WeightLifting.prototype.play = function () {
    console.log('我在玩'+this.name);
}

// 跑步類
var Running = function (name) {
    this.name = name;
};
// 抽象工廠實現對速度運動的繼承
Sport(Running,'Speed');
Running.prototype.play = function () {
    console.log('我在'+this.name);
}

// 抽象工廠模式實現
var basketBall = new BasketBall('籃球');
console.log(basketBall.type);//ball
basketBall.play();
var weightLifting = new WeightLifting('舉重');
console.log(weightLifting.type);//power
weightLifting.play();
var running = new Running('跑步');
console.log(running.type);//ball
running.play();

/** 輸出結果
 * ball
 * 我在玩籃球
 * power
 * 我在玩舉重
 * speed
 * 我在跑步
 */


// # 抽象工廠模式end

這段栗子先是建立一個運動類的抽象工廠,經過這個暴露外部調用的接口,傳遞2個參數,一個是subType,當前實例化的對象,也就是子類,
一個是superType,須要繼承的父類(抽象類)的名稱,在工廠函數中實現了子類對父類的繼承。

在繼承過程當中有一個地方須要注意,就是在對過渡類繼承的時候,咱們不是繼承父類原型,而是經過new關鍵字複製父類的一個實列,這樣作的目的是過渡類不只僅繼承父類的原型方法,還須要繼承父類的對象屬性,因此經過new關鍵字的方式實現了繼承。

而後經過在抽象工廠類上面進行擴展對應的抽象類,也就是咱們須要經過繼承的父類,我這邊添加了3個抽象類Ball,Power,Speed,分別給抽象類指定了type屬性,還有方法play,既然建立了抽象類,那麼下面就是開始使用抽象工廠去建立子類,這邊分別對Ball,Power,Speed 3個抽象類進行了實現建立了BasketBall(球類),WeightLifting(力量),Running(速度)3個子類3個子類分別對play方法進行了實現最後就是對於子類的調用實現,在實現子類調用的時候,

咱們能夠獲取到繼承的父類當中對應的type

抽象工廠模式的優勢:

當一個產品族中的多個對象被設計成一塊兒工做時,它可以保證客戶端始終只使用同一個產品族中的對象。

增長新的具體工廠和產品族很方便,無須修改已有系統,符合「開閉原則」。

抽象工廠模式的缺點:

開閉原則的傾斜性(增長新的工廠和產品族容易,增長新的產品等級結構麻煩)。

增長新的產品等級結構:對於增長新的產品等級結構,須要修改全部的工廠角色,包括抽象工廠類,在全部的工廠類中都須要增長生產新產品的方法,不能很好地支持「開閉原則」。

抽象工廠模式的適用狀況:

在如下狀況下可使用抽象工廠模式:

  • 一個系統不該當依賴於產品類實例如何被建立、組合和表達的細節,這對於全部類型的工廠模式都是重要的。
  • 系統中有多於一個的產品族,而每次只使用其中某一產品族。屬於同一個產品族的產品將在一塊兒使用,這一約束必須在系統的設計中體現出來。
  • 系統提供一個產品類的庫,全部的產品以一樣的接口出現,從而使客戶端不依賴於具體實現。

抽象工廠模式總結

  • 抽象工廠模式是全部形式的工廠模式中最爲抽象和最具通常性的一種形態。抽象工廠模式與工廠方法模式最大的區別在於,工廠方法模式針對的是一個產品等級結構,而抽象工廠模式則須要面對多個產品等級結構。
  • 抽象工廠模式適用狀況包括:一個系統不該當依賴於產品類實例如何被建立、組合和表達的細節;系統中有多於一個的產品族,而每次只使用其中某一產品族;屬於同一個產品族的產品將在一塊兒使用;系統提供一個產品類的庫,全部的產品以一樣的接口出現,從而使客戶端不依賴於具體實現。

4.三大工廠模式的關聯性

  • 當抽象工廠模式中每個具體工廠類只建立一個產品對象,也就是隻存在一個產品等級結構時,抽象工廠模式轉換成工廠方法模式;
  • 當工廠方法模式中抽象工廠與具體工廠合併,提供一個統一的工廠來建立產品對象,並將建立對象的工廠方法設計爲靜態方法時,工廠方法模式退化成簡單工廠模式。
注:根據實際適用狀況去選擇對應的工廠模式
相關文章
相關標籤/搜索