最近閱讀了幾本設計模式方面的書籍,學習之餘整理下來,方便之後的概括和梳理javascript
創造工廠模式是一種建立性模式
,也就是一種建立對象的最佳實踐.首先咱們須要理解:html
想象一個場景:若是你要求去買一些東西:板燒雞腿漢堡
,可樂
和薯條
,那麼人們會很是天然的跑去麥當勞去購買對吧.java
爲何咱們會想到去麥當勞呢?由於這些東西都是一類食物,而後麥當勞做爲一個'工廠',能夠一條龍的提供給消費者,若是沒有麥當勞,那麼咱們須要分別去可樂,薯條和板燒雞腿漢堡的店面去分別買這些食物,那麼購買效率會很低.因此能夠說麥當勞就是一個銷售食物的工廠模式.設計模式
因此咱們能夠這樣理解工廠模式,把相關的多個類(薯條,可樂等)提供一個統一入口的一個模式,讓你從一個入口就能夠得到多個類,提升工做效率.安全
可是對於工廠模式也會有三種類型的實現方式,分別是:簡單工廠模式,工廠方法模式和抽象工廠模式.它們分別是在各自基礎上有必定的改進.函數
也被叫作靜態工廠模式(Simple Factory Patter),主要用於建立同一類的對象
.學習
適用狀況:若是被要求寫一些球類的實現,那麼通常狀況的話咱們會這樣實現:this
var Football = function(){ this.name = "football"; .... } var Basketball = function(){ this.name = "basketball"; .... }
這種寫法有一些缺陷:返回了多個類,不便於他人使用.
所以咱們考慮把這些相似的類封裝到一個工廠裏面,也就有了咱們的簡單工廠模式:prototype
var BallFactory; !(function(){ BallFactory = function(type,cfg){ var Football = function(cfg){ this.name = 'football'; console.log(this.name + " in the prototype"); }; Football.prototype = { call:function(){console.log(this.name)}, sell:function(){} }; var Basketball = function(cfg) { this.name = "basketball"; console.log(this.name); }; var cfg = cfg ||{}; switch(type){ case 'football': return new Football(cfg); break; case 'basketball': return new Basketball(cfg); break; } }; })(); var aFootball = BallFactory('football'); aFootball.call();
所以使用BallFactory把這些內容包裹起來給其餘人使用就會避免返回了多個類的問題,因此這就是簡單工廠模式想解決的問題:統一建立的入口
.設計
固然在實際的使用過程當中,咱們會使用一些其它技巧:
若是工廠的產品中有不少重複部分,那麼咱們須要把重複的部分抽象出來成爲共同的部分,不一樣的部分放入switch裏面:
var GetChildren = function(cfg){ cfg = cfg||{}; this.name = cfg.name; this.height = cfg.height; this.speak = function(){}; //抽離出不一樣的部分 switch(cfg.gender){ case "boy": this.gender = cfg.gender; this.moustouch = .... .....; //特有部分 break; case "girl": this.gender = cfg.gender; ....... break; } return this; } var aBoy = GetChildren({.....});
在簡單工廠模式的基礎上,咱們已經解決了入口不統一的問題,可是還有一個問題沒有解決:
加入一個新的類須要修改多部分:首先咱們須要在BallFactory工廠內部加入如何實現,而後加到switch部分;因此這是一次修改的需求,咱們須要修改多個地方.
那麼咱們看能不能嘗試更抽象一點,儘量減小須要修改的地方;
var BallFactory = function(type,cfg){ this.name = cfg.name; //共同的部分放在這裏 return this[type](cfg); }; BallFactory.prototype = { football:function(cfg){ console.log("這裏加入和football相關的獨特內容" +this.name); }, basketball:function(cfg) { console.log("這裏加入和basketball相關的獨特內容" +this.name); } }; var aBall = new BallFactory("football",{name:"football"}); //football in the prototype
因此這裏加入了一個return this[type](cfg)
的方法自動代替了以前的switch的方法.之後須要加入內容只須要修改BallFactory的prototype就能夠了.
固然咱們還能夠添加一種安全模式
來解決若是不在構造函數前面加上new的話,會報錯的問題.解決的思路實際上是把new封裝在構造函數以內:
var BallFactory = function(type,cfg){ if(!(this instanceof BallFactory)){ return new BallFactory(type,cfg); //多一行判斷即:若是沒有帶new,我本身幫你new一個返回就好; } this.name = cfg.name; return this[type](cfg); }; var aBall = BallFactory("football",{name:"football"}); //這裏若是掉了new也會正常執行;
因此,咱們能夠看到的是,咱們使用簡單工廠模式解決了入口不統一的問題,而後使用工廠模式解決了修改地點不統一的問題
通常來講,抽象工廠在大型項目的使用更多,大概的思路是在父類裏面設計好接口(沒有具體實現),具體的實現等到了子類再重寫.
這裏借用一個張容銘的<JavaScript設計模式>的一個例子:
var Car = function(){}; Car.prototype = { getPrice:function(){ throw new Error("抽象方法不能調用")}, getSpeed:function(){ throw new Error("抽象方法不能調用")} }; //這裏使用Object.create()繼承,子類到父類中會多一箇中間過渡函數Temp(){};防止在子類的prototype覆蓋父類;可見參考資料 aBMW = Object.create(Car.prototype); aBMW.getPrice(); // 抽象方法不能調用 aBMW.getPrice = function(){ console.log("I am getting price"); }; aBMW.getPrice(); //I am getting price
父類定義好接口,具體實現延遲到子類才實現.
因此總結來講:
簡單工廠模式解決了入口不統一的問題,
工廠模式解決了修改地點不統一的問題,
抽象工廠模式解決了子類實現不規範的問題