工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情胀蛮,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。
簡(jiǎn)單的工廠模式可以理解為解決多個(gè)相似的問(wèn)題;這也是她的優(yōu)點(diǎn);比如如下代碼:
function CreatePerson(name,age,sex) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sex = sex;
obj.sayName = function(){
return this.name;
}
return obj;
}
var p1 = new CreatePerson("longen",'28','男');
var p2 = new CreatePerson("tugenhua",'27','女');
console.log(p1.name); // longen
console.log(p1.age); // 28
console.log(p1.sex); // 男
console.log(p1.sayName()); // longen
console.log(p2.name); // tugenhua
console.log(p2.age); // 27
console.log(p2.sex); // 女
console.log(p2.sayName()); // tugenhua
// 返回都是object 無(wú)法識(shí)別對(duì)象的類型 不知道他們是哪個(gè)對(duì)象的實(shí)列
console.log(typeof p1); // object
console.log(typeof p2); // object
console.log(p1 instanceof Object); // true
如上代碼:函數(shù)CreatePerson能接受三個(gè)參數(shù)name,age,sex等參數(shù)刁憋,可以無(wú)數(shù)次調(diào)用這個(gè)函數(shù)珍昨,每次返回都會(huì)包含三個(gè)屬性和一個(gè)方法的對(duì)象。
工廠模式是為了解決多個(gè)類似對(duì)象聲明的問(wèn)題;也就是為了解決實(shí)列化對(duì)象產(chǎn)生重復(fù)的問(wèn)題动羽。
優(yōu)點(diǎn):能解決多個(gè)相似的問(wèn)題包帚。
缺點(diǎn):不能知道對(duì)象識(shí)別的問(wèn)題(對(duì)象的類型不知道)。
復(fù)雜的工廠模式定義是:將其成員對(duì)象的實(shí)列化推遲到子類中运吓,子類可以重寫(xiě)父類接口方法以便創(chuàng)建的時(shí)候指定自己的對(duì)象類型渴邦。
父類只對(duì)創(chuàng)建過(guò)程中的一般性問(wèn)題進(jìn)行處理,這些處理會(huì)被子類繼承拘哨,子類之間是相互獨(dú)立的谋梭,具體的業(yè)務(wù)邏輯會(huì)放在子類中進(jìn)行編寫(xiě)。
父類就變成了一個(gè)抽象類倦青,但是父類可以執(zhí)行子類中相同類似的方法瓮床,具體的業(yè)務(wù)邏輯需要放在子類中去實(shí)現(xiàn)产镐;比如我現(xiàn)在開(kāi)幾個(gè)自行車店,那么每個(gè)店都有幾種型號(hào)的自行車出售癣亚。我們現(xiàn)在來(lái)使用工廠模式來(lái)編寫(xiě)這些代碼;
父類的構(gòu)造函數(shù)如下:
// 定義自行車的構(gòu)造函數(shù)
var BicycleShop = function(){};
BicycleShop.prototype = {
constructor: BicycleShop,
/*
* 買自行車這個(gè)方法
* @param {model} 自行車型號(hào)
*/
sellBicycle: function(model){
var bicycle = this.createBicycle(model);
// 執(zhí)行A業(yè)務(wù)邏輯
bicycle.A();
// 執(zhí)行B業(yè)務(wù)邏輯
bicycle.B();
return bicycle;
},
createBicycle: function(model){
throw new Error("父類是抽象類不能直接調(diào)用,需要子類重寫(xiě)該方法");
}
};
上面是定義一個(gè)自行車抽象類來(lái)編寫(xiě)工廠模式的實(shí)列述雾,定義了createBicycle這個(gè)方法蓬豁,但是如果直接實(shí)例化父類,調(diào)用父類中的這個(gè)createBicycle方法,會(huì)拋出一個(gè)error地粪,因?yàn)楦割愂且粋€(gè)抽象類,他不能被實(shí)列化琐谤,只能通過(guò)子類來(lái)實(shí)現(xiàn)這個(gè)方法,實(shí)現(xiàn)自己的業(yè)務(wù)邏輯斗忌,下面我們來(lái)定義子類质礼,我們學(xué)會(huì)如何使用工廠模式重新編寫(xiě)這個(gè)方法,首先我們需要繼承父類中的成員织阳,然后編寫(xiě)子類;如下代碼:
// 定義自行車的構(gòu)造函數(shù)
var BicycleShop = function(name){
this.name = name;
this.method = function(){
return this.name;
}
};
BicycleShop.prototype = {
constructor: BicycleShop,
/*
* 買自行車這個(gè)方法
* @param {model} 自行車型號(hào)
*/
sellBicycle: function(model){
var bicycle = this.createBicycle(model);
// 執(zhí)行A業(yè)務(wù)邏輯
bicycle.A();
// 執(zhí)行B業(yè)務(wù)邏輯
bicycle.B();
return bicycle;
},
createBicycle: function(model){
throw new Error("父類是抽象類不能直接調(diào)用眶蕉,需要子類重寫(xiě)該方法");
}
};
// 實(shí)現(xiàn)原型繼承
function extend(Sub,Sup) {
//Sub表示子類,Sup表示超類
// 首先定義一個(gè)空函數(shù)
var F = function(){};
// 設(shè)置空函數(shù)的原型為超類的原型
F.prototype = Sup.prototype;
// 實(shí)例化空函數(shù)唧躲,并把超類原型引用傳遞給子類
Sub.prototype = new F();
// 重置子類原型的構(gòu)造器為子類自身
Sub.prototype.constructor = Sub;
// 在子類中保存超類的原型,避免子類與超類耦合
Sub.sup = Sup.prototype;
if(Sup.prototype.constructor === Object.prototype.constructor) {
// 檢測(cè)超類原型的構(gòu)造器是否為原型自身
Sup.prototype.constructor = Sup;
}
}
var BicycleChild = function(name){
this.name = name;
// 繼承構(gòu)造函數(shù)父類中的屬性和方法
BicycleShop.call(this,name);
};
// 子類繼承父類原型方法
extend(BicycleChild,BicycleShop);
// BicycleChild 子類重寫(xiě)父類的方法
BicycleChild.prototype.createBicycle = function(){
var A = function(){
console.log("執(zhí)行A業(yè)務(wù)操作");
};
var B = function(){
console.log("執(zhí)行B業(yè)務(wù)操作");
};
return {
A: A,
B: B
}
}
var childClass = new BicycleChild("龍恩");
console.log(childClass);
實(shí)例化子類造挽,然后打印出該實(shí)例, 如下截圖所示:
console.log(childClass.name); // 龍恩
// 下面是實(shí)例化后 執(zhí)行父類中的sellBicycle這個(gè)方法后會(huì)依次調(diào)用父類中的A
// 和B方法;A方法和B方法依次在子類中去編寫(xiě)具體的業(yè)務(wù)邏輯弄痹。
childClass.sellBicycle("mode"); // 打印出
執(zhí)行A業(yè)務(wù)操作和執(zhí)行B業(yè)務(wù)操作
上面只是"龍恩"自行車這么一個(gè)型號(hào)的饭入,如果需要生成其他型號(hào)的自行車的話,可以編寫(xiě)其他子類肛真,工廠模式最重要的優(yōu)點(diǎn)是:可以實(shí)現(xiàn)一些相同的方法谐丢,這些相同的方法我們可以放在父類中編寫(xiě)代碼,那么需要實(shí)現(xiàn)具體的業(yè)務(wù)邏輯蚓让,那么可以放在子類中重寫(xiě)該父類的方法乾忱,去實(shí)現(xiàn)自己的業(yè)務(wù)邏輯;使用專業(yè)術(shù)語(yǔ)來(lái)講的話有2點(diǎn):第一:弱化對(duì)象間的耦合历极,防止代碼的重復(fù)窄瘟。在一個(gè)方法中進(jìn)行類的實(shí)例化,可以消除重復(fù)性的代碼执解。第二:重復(fù)性的代碼可以放在父類去編寫(xiě)寞肖,子類繼承于父類的所有成員屬性和方法纲酗,子類只專注于實(shí)現(xiàn)自己的業(yè)務(wù)邏輯衰腌。