Javascript設計模式-工廠模式 我理解工廠模式,就是把相關的多個類提供一個統一入口的一個模式,讓你從一個入口就可以獲得多個類,提高工作效率. 但是對於工廠模式也會有三種類型的實現方式,分別是:簡單工廠模式,工廠方法模式和抽象工廠模式.它們分別是在各自基礎上有一定的改進. 簡單工廠模式 也被叫 ...
Javascript設計模式-工廠模式
我理解工廠模式,就是把相關的多個類提供一個統一入口的一個模式,讓你從一個入口就可以獲得多個類,提高工作效率.
但是對於工廠模式也會有三種類型的實現方式,分別是:簡單工廠模式,工廠方法模式和抽象工廠模式.它們分別是在各自基礎上有一定的改進.
簡單工廠模式
也被叫做靜態工廠模式(Simple Factory Patter),主要用於創建同一類的對象
.
適用情況:如果被要求寫一些球類的實現,那麼一般情況的話我們會這樣實現:
var Football = function(){
this.name = "football";
....
}
var Basketball = function(){
this.name = "basketball";
....
}
這種寫法有一些缺陷:返回了多個類,不便於他人使用.
因此我們考慮把這些類似的類封裝到一個工廠裡面,也就有了我們的簡單工廠模式:
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
父類定義好介面,具體實現延遲到子類才實現.
所以總結來說:
簡單工廠模式解決了入口不統一的問題,
工廠模式解決了修改地點不統一的問題,
抽象工廠模式解決了子類實現不規範的問題。
目前我們新改版的移動端表單塊邏輯和渲染分離,也類似於把一個表單頁面抽離成一個工廠,工廠裡面有二十多個不同的控制項,每個控制項去繼承表單這個類。