JavaScript設(shè)計(jì)模式--簡(jiǎn)單工廠模式定義與應(yīng)用案例詳解
本文實(shí)例講述了JavaScript設(shè)計(jì)模式--簡(jiǎn)單工廠模式定義與應(yīng)用。分享給大家供大家參考,具體如下:
一,介紹
工廠模式創(chuàng)建對(duì)象(視為工廠里的產(chǎn)品)時(shí)無(wú)需指定創(chuàng)建對(duì)象的具體類(lèi)。
工廠模式定義一個(gè)用于創(chuàng)建對(duì)象的接口,這個(gè)接口由子類(lèi)決定實(shí)例化哪一個(gè)類(lèi)。該模式使一個(gè)類(lèi)的實(shí)例化延遲到了子類(lèi)。而子類(lèi)可以重寫(xiě)接口方法以便創(chuàng)建的時(shí)候指定自己的對(duì)象類(lèi)型。
在這里將工廠簡(jiǎn)單分為三種:
(1)簡(jiǎn)單工廠:通過(guò)第三方的類(lèi)完成松耦合的任務(wù)。
(2)復(fù)雜工廠:通過(guò)把實(shí)例化的任務(wù)交給子類(lèi)來(lái)完成的,用以到達(dá)松耦合的目的。
(3)超級(jí)工廠:通過(guò)eval()來(lái)完成智能工廠。
工廠的目的:在于判斷接口最終用哪個(gè)類(lèi)實(shí)例化(故與接口密不可分)。
使用工廠最終達(dá)到的效果是:多態(tài),和類(lèi)與類(lèi)之間的松耦合。
二,正文部分
工廠模式與接口是密不可分的所以我們需要先引入接口文件和繼承類(lèi)文件
(1)接口文件:
//定義一個(gè)靜態(tài)方法來(lái)實(shí)現(xiàn)接口與實(shí)現(xiàn)類(lèi)的直接檢驗(yàn) //靜態(tài)方法不要寫(xiě)出Interface.prototype ,因?yàn)檫@是寫(xiě)到接口的原型鏈上的 //我們要把靜態(tài)的函數(shù)直接寫(xiě)到類(lèi)層次上 //(1)定義一個(gè)接口類(lèi) var Interface=function (name,methods) {//name:接口名字 if(arguments.length<2){ alert("必須是兩個(gè)參數(shù)") } this.name=name; this.methods=[];//定義一個(gè)空數(shù)組裝載函數(shù)名 for(var i=0;i<methods.length;i++){ if(typeof methods[i]!="string"){ alert("函數(shù)名必須是字符串類(lèi)型"); }else { this.methods.push( methods[i]); } } }; Interface.ensureImplement=function (object) { if(arguments.length<2){ throw new Error("參數(shù)必須不少于2個(gè)") return false; } for(var i=1;i<arguments.length;i++){ var inter=arguments[i]; //如果是接口就必須是Interface類(lèi)型 if(inter.constructor!=Interface){ throw new Error("如果是接口類(lèi)的話,就必須是Interface類(lèi)型"); } //判斷接口中的方法是否全部實(shí)現(xiàn) //遍歷函數(shù)集合 for(var j=0;j<inter.methods.length;j++){ var method=inter.methods[j];//接口中所有函數(shù) //object[method]傳入的函數(shù) //最終是判斷傳入的函數(shù)是否與接口中所用函數(shù)匹配 if(!object[method]||typeof object[method]!="function" ){//實(shí)現(xiàn)類(lèi)中必須有方法名字與接口中所用方法名相同 throw new Error("實(shí)現(xiàn)類(lèi)中沒(méi)有完全實(shí)現(xiàn)接口中的所有方法") } } } }
(2)繼承文件
/*創(chuàng)建extend函數(shù)為了程序中所有的繼承操作*/ //subClass:子類(lèi) superClass:超類(lèi) function extend(subClass,superClass) { //1,使子類(lèi)原型屬性等于父類(lèi)的原型屬性 //初始化一個(gè)中間空對(duì)象,目的是為了轉(zhuǎn)換主父關(guān)系 var F = function () {}; F.prototype = superClass.prototype; //2, 讓子類(lèi)繼承F subClass.prototype = new F(); subClass.prototype.constructor = subClass; //3,為子類(lèi)增加屬性 superClass ==》原型鏈的引用 subClass.superClass = superClass.prototype; //4,增加一個(gè)保險(xiǎn),就算你的原型類(lèi)是超類(lèi)(Object)那么也要把你的構(gòu)造函數(shù)級(jí)別降下來(lái) if (superClass.prototype.constructor == Object.prototype.constructor) { superClass.prototype.constructor = superClass; } }
通過(guò)下面的例子,逐步引進(jìn)工廠模式及改進(jìn)工廠模式
1,工廠模式的引入,
(1)創(chuàng)建接口對(duì)象
var Pet=new Interface("Pet",["eat","run","sing","register"]);
(2)定義一個(gè)寵物店類(lèi)并在prototype上進(jìn)行擴(kuò)展
var PetShop=function () {} PetShop.prototype={ //出售寵物的方法 sellPet:function (kind) { //寵物對(duì)象 var pet; //寵物種類(lèi) switch (kind){ case 'dog': pet=new Dog(); break; case 'cat': pet=new Cat(); break; case 'pig': pet=new Pig(); break; default: pet=new Bird(); } //驗(yàn)證接口 Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)現(xiàn)接口Pet里面全部的方法 (對(duì)象,接口) pet.eat(); pet.register(); return pet; } }
(3)分析寵物的一些特點(diǎn)可以將一些公共的部分提取出來(lái)(這里只是簡(jiǎn)單的提?。?/p>
//基類(lèi) 有共同的提出來(lái) function basePet() { this.register=function () { document.write("寵物登記...<br>"); } this.eat=function () { document.write("寵物吃飯...<br>"); } }
(4)各個(gè)實(shí)現(xiàn)類(lèi) ---這里是各種動(dòng)物
function Dog() { Dog.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口部分 this.run=function () { document.write("小狗跑......<br>") } this.sing=function () { document.write("小狗唱歌......<br>") } } function Cat() { Cat.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口部分 this.run=function () { document.write("小貓跑......<br>") } this.sing=function () { document.write("小貓唱歌......<br>") } } function Pig() { Pig.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口部分 this.run=function () { document.write("小豬跑......<br>") } this.sing=function () { document.write("小豬唱歌......<br>") } } function Bird() { Bird.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口部分 this.run=function () { document.write("小鳥(niǎo)跑......<br>") } this.sing=function () { document.write("小鳥(niǎo)唱歌......<br>") } }
(5)各個(gè)實(shí)現(xiàn)類(lèi)繼承基類(lèi)
//繼承
extend(Dog,basePet); extend(Cat,basePet); extend(Pig,basePet); extend(Bird,basePet);
(6)創(chuàng)建寵物的開(kāi)始賣(mài)寵物
var newPetShop=new PetShop(); var flowerPig=newPetShop.sellPet("pig"); flowerPig.run();
結(jié)果為:
總結(jié)一下,上述好像沒(méi)怎么體現(xiàn)有關(guān)工廠之類(lèi)的,我們應(yīng)該注意到這么一個(gè)問(wèn)題就是:當(dāng)需要增加一個(gè)新品種寵物時(shí),我們需要修改 '寵物店類(lèi)',耦合度較高。
為了解決這個(gè)問(wèn)題我們使用簡(jiǎn)單工廠模式來(lái)解決。
2,簡(jiǎn)單工廠模式(針對(duì)上述的改進(jìn))
(1)接口文件與繼承文件的的引入 同上面
(2)靜態(tài)工廠
//使用工廠方式創(chuàng)建寵物對(duì)象 // 靜態(tài)工廠 var factoryPet={ //出售寵物的方法 getPet:function (kind) { //寵物對(duì)象 var pet; //寵物種類(lèi) switch (kind){ case 'dog': pet=new Dog(); break; case 'cat': pet=new Cat(); break; case 'pig': pet=new Pig(); break; default: pet=new Bird(); } //驗(yàn)證接口 Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)行接口Pet里面全部的方法 return pet; } }
(3)利用工廠創(chuàng)建寵物店對(duì)象
var factoryPetShop=function () {} factoryPetShop.prototype={ getPet:function (kind) { var pet=factoryPet.getPet(kind); pet.eat(); pet.register(); return pet; } }
(4)從寵物店購(gòu)買(mǎi)寵物實(shí)現(xiàn)
var newPetShop=new factoryPetShop(); var flowerCat=newPetShop.getPet("cat"); flowerCat.sing();
(5)使用簡(jiǎn)單工廠實(shí)現(xiàn)的全部代碼(數(shù)字標(biāo)號(hào)表示其思考的先后順序)
(function () { //(2)接口調(diào)用 var Pet=new Interface("Pet",["eat","run","sing","register"]); //(3)基類(lèi) 分析后有共同的提出來(lái)作為基類(lèi) function basePet() { this.register=function () { document.write("寵物登記。。。。<br>"); } this.eat=function () { document.write("寵物吃飯。。。。<br>"); } } //(4)實(shí)現(xiàn)類(lèi) 繼承基類(lèi)+接口實(shí)現(xiàn) function Dog() { Dog.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小狗跑......<br>") } this.sing=function () { document.write("小狗唱歌......<br>") } } function Cat() { Cat.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小貓跑......<br>") } this.sing=function () { document.write("小貓唱歌......<br>") } } function Pig() { Pig.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小豬跑......<br>") } this.sing=function () { document.write("小豬唱歌......<br>") } } function Bird() { Bird.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小鳥(niǎo)跑......<br>") } this.sing=function () { document.write("小鳥(niǎo)唱歌......<br>") } } //繼承 extend(Dog,basePet); extend(Cat,basePet); extend(Pig,basePet); extend(Bird,basePet); //(1)使用工廠方式創(chuàng)建寵物對(duì)象 // 靜態(tài)工廠 var factoryPet={ //出售寵物的方法 getPet:function (kind) { //寵物對(duì)象 var pet; //寵物種類(lèi) switch (kind){ case 'dog': pet=new Dog(); break; case 'cat': pet=new Cat(); break; case 'pig': pet=new Pig(); break; default: pet=new Bird(); } //驗(yàn)證接口 Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)行接口Pet里面全部的方法 return pet; } } //(5)利用工廠的寵物店對(duì)象(寵物店買(mǎi)寵物) var factoryPetShop=function () {} factoryPetShop.prototype={ getPet:function (kind) { var pet=factoryPet.getPet(kind); pet.eat(); pet.register(); return pet; } } //(6)從寵物店購(gòu)買(mǎi)寵物 var newPetShop=new factoryPetShop();//寵物工廠 var flowerCat=newPetShop.getPet("cat");//從寵物工廠中得到寵物 flowerCat.sing(); })()
總結(jié)一下,上述看似完美,但是任有問(wèn)題存在:比如說(shuō):張三的寵物店想賣(mài)哈士奇,李四的寵物店想賣(mài)鳥(niǎo)時(shí),這樣的話,寵物都是通過(guò)一個(gè)工廠生產(chǎn)的,并不一定滿足各個(gè)賣(mài)家的需求。
所以我們需要根據(jù)各個(gè)廠家的需求,有不同的工廠,各個(gè)賣(mài)家可以根據(jù)自己需求使用不同的工廠(其實(shí)是利用不同子類(lèi)實(shí)現(xiàn)各自合適的工廠),用于滿足每個(gè)寵物店的不同。
于是我們有了復(fù)雜的工廠用來(lái)解決該問(wèn)題。
3,復(fù)雜工廠:通過(guò)把實(shí)例化的任務(wù)交給子類(lèi)來(lái)完成的,用以到達(dá)松耦合的目的。
此處同樣是根據(jù)上述進(jìn)行改進(jìn)的,還是簡(jiǎn)單的說(shuō)明一下實(shí)現(xiàn)過(guò)程
(1)在html中將接口文件的引進(jìn),代碼為
//定義一個(gè)靜態(tài)方法來(lái)實(shí)現(xiàn)接口與實(shí)現(xiàn)類(lèi)的直接檢驗(yàn) //靜態(tài)方法不要寫(xiě)出Interface.prototype ,因?yàn)檫@是寫(xiě)到接口的原型鏈上的 //我們要把靜態(tài)的函數(shù)直接寫(xiě)到類(lèi)層次上 //定義一個(gè)接口類(lèi) var Interface=function (name,methods) {//name:接口名字 if(arguments.length<2){ alert("必須是兩個(gè)參數(shù)") } this.name=name; this.methods=[];//定義一個(gè)空數(shù)組裝載函數(shù)名 for(var i=0;i<methods.length;i++){ if(typeof methods[i]!="string"){ alert("函數(shù)名必須是字符串類(lèi)型"); }else { this.methods.push( methods[i]); } } }; Interface.ensureImplement=function (object) { if(arguments.length<2){ throw new Error("參數(shù)必須不少于2個(gè)") return false; } for(var i=1;i<arguments.length;i++){ var inter=arguments[i]; //如果是接口就必須是Interface類(lèi)型 if(inter.constructor!=Interface){ throw new Error("如果是接口類(lèi)的話,就必須是Interface類(lèi)型"); } //判斷接口中的方法是否全部實(shí)現(xiàn) //遍歷函數(shù)集合 for(var j=0;j<inter.methods.length;j++){ var method=inter.methods[j];//接口中所有函數(shù) //object[method]傳入的函數(shù) //最終是判斷傳入的函數(shù)是否與接口中所用函數(shù)匹配 if(!object[method]||typeof object[method]!="function" ){//實(shí)現(xiàn)類(lèi)中必須有方法名字與接口中所用方法名相同 throw new Error("實(shí)現(xiàn)類(lèi)中沒(méi)有完全實(shí)現(xiàn)接口中的所有方法") } } } }
(2)在html中將繼承文件引入,代碼如下,
/*創(chuàng)建extend函數(shù)為了程序中所有的繼承操作*/ //subClass:子類(lèi) superClass:超類(lèi) function extend(subClass,superClass) { //1,使子類(lèi)原型屬性等于父類(lèi)的原型屬性 //初始化一個(gè)中間空對(duì)象,目的是為了轉(zhuǎn)換主父關(guān)系 var F = function () {}; F.prototype = superClass.prototype; //2, 讓子類(lèi)繼承F subClass.prototype = new F(); subClass.prototype.constructor = subClass; //3,為子類(lèi)增加屬性 superClass ==》原型鏈的引用 subClass.superClass = superClass.prototype; //4,增加一個(gè)保險(xiǎn),就算你的原型類(lèi)是超類(lèi)(Object)那么也要把你的構(gòu)造函數(shù)級(jí)別降下來(lái) if (superClass.prototype.constructor == Object.prototype.constructor) { superClass.prototype.constructor = superClass; } }
(3)分析各個(gè)類(lèi)提出相同的部分作為基類(lèi),基類(lèi)代碼如下
//基類(lèi) 分析后有共同的提出來(lái)作為基類(lèi) function basePet() { this.register=function () { document.write("寵物登記。。。。<br>"); }; this.eat=function () { document.write("寵物吃飯。。。。<br>"); } }
(4)各個(gè)具體的實(shí)現(xiàn)類(lèi):繼承基類(lèi)+接口實(shí)現(xiàn)
//各個(gè)寵物類(lèi)(實(shí)現(xiàn)類(lèi)) 繼承基類(lèi)+接口實(shí)現(xiàn) function Dog() { Dog.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小狗跑......<br>") } this.sing=function () { document.write("小狗唱歌......<br>") } } function Cat() { Cat.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小貓跑......<br>") } this.sing=function () { document.write("小貓唱歌......<br>") } } function Pig() { Pig.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小豬跑......<br>") } this.sing=function () { document.write("小豬唱歌......<br>") } } function Bird() { Bird.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小鳥(niǎo)跑......<br>") }; this.sing=function () { document.write("小鳥(niǎo)唱歌......<br>") } }
(5)實(shí)現(xiàn)類(lèi)與基類(lèi)的繼承實(shí)現(xiàn),代碼如下(調(diào)用extend())
extend(Dog,basePet);//動(dòng)物狗繼承基類(lèi) extend(Cat,basePet); extend(Pig,basePet); extend(Bird,basePet);
(6)將商店抽取出來(lái),做成抽象類(lèi),代碼如下
//把核心商店抽取出來(lái) var petShop=function () {}; petShop.prototype={//模擬抽象類(lèi) 需要被子類(lèi)覆蓋 getPet:function (kind){ var pet=this.getpet(kind); pet.eat(); pet.register(); return pet; }, getpet:function (model){ throw new Error("該類(lèi)是抽象類(lèi),不能實(shí)例化") } };
(7)利用子類(lèi)來(lái)滿足各個(gè)商家的不同類(lèi)型寵物店的實(shí)現(xiàn) ,代碼如下
//利用子類(lèi)來(lái)滿足之前的需求(多態(tài)) var oneShop=function () { } extend(oneShop,petShop);//繼承 //覆寫(xiě)方法 oneShop.prototype.getpet=function (model) { //寵物對(duì)象 var pet; //寵物種類(lèi) switch (model){ case 'dog': pet=new Dog(); break; default: pet=new Bird(); } //驗(yàn)證接口 Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)行接口Pet里面全部的方法 pet.eat(); pet.register(); return pet; };
同上,這個(gè)也是一個(gè)不同的子類(lèi)
twoShop=function () {}; extend(twoShop,petShop);//商店的繼承 //覆寫(xiě)方法 twoShop.prototype.getPet=function (model) { //寵物對(duì)象 var pet; //寵物種類(lèi) switch (kind){ case 'pig': pet=new Pig(); break; default: pet=new Bird(); } //驗(yàn)證接口 Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)行接口Pet里面全部的方法 pet.eat(); pet.register(); return pet; };
(8) 使用,實(shí)質(zhì)是子類(lèi)對(duì)父類(lèi)的實(shí)例化
這里實(shí)現(xiàn)其中一個(gè)寵物店,另外一個(gè)同理。
//子類(lèi)對(duì)父類(lèi)的實(shí)例化 var jim=new oneShop(); var pig= jim.getpet("dog"); pig.run(); pig.sing()
(9)上述代碼綜合在一起為,代碼如下
(function () { //(2)接口調(diào)用 var Pet=new Interface("Pet",["eat","run","sing","register"]); //(1)基類(lèi) 分析后有共同的提出來(lái)作為基類(lèi) function basePet() { this.register=function () { document.write("寵物登記。。。。<br>"); }; this.eat=function () { document.write("寵物吃飯。。。。<br>"); } } //(3)實(shí)現(xiàn)類(lèi) 繼承基類(lèi)+接口實(shí)現(xiàn) function Dog() { Dog.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小狗跑......<br>") } this.sing=function () { document.write("小狗唱歌......<br>") } } function Cat() { Cat.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小貓跑......<br>") } this.sing=function () { document.write("小貓唱歌......<br>") } } function Pig() { Pig.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小豬跑......<br>") } this.sing=function () { document.write("小豬唱歌......<br>") } } function Bird() { Bird.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小鳥(niǎo)跑......<br>") }; this.sing=function () { document.write("小鳥(niǎo)唱歌......<br>") } } //繼承 extend(Dog,basePet);//寵物的繼承 extend(Cat,basePet); extend(Pig,basePet); extend(Bird,basePet); //(4)把核心商店抽取出來(lái) var petShop=function () {}; petShop.prototype={//模擬抽象類(lèi) 需要被子類(lèi)覆蓋 getPet:function (kind){ var pet=this.getpet(kind); pet.eat(); pet.register(); return pet; }, getpet:function (model){ throw new Error("該類(lèi)是抽象類(lèi),不能實(shí)例化") } }; //(5)商店1 利用子類(lèi)來(lái)滿足之前的需求(多態(tài)) var oneShop=function () { } extend(oneShop,petShop);//繼承 //覆寫(xiě)方法 oneShop.prototype.getpet=function (model) { //寵物對(duì)象 var pet; //寵物種類(lèi) switch (model){ case 'dog': pet=new Dog(); break; default: pet=new Bird(); } //驗(yàn)證接口 Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)行接口Pet里面全部的方法 pet.eat(); pet.register(); return pet; }; //(5)商店2 twoShop=function () {}; extend(twoShop,petShop);//商店的繼承 //覆寫(xiě)方法 twoShop.prototype.getPet=function (model) { //寵物對(duì)象 var pet; //寵物種類(lèi) switch (kind){ case 'pig': pet=new Pig(); break; default: pet=new Bird(); } //驗(yàn)證接口 Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)行接口Pet里面全部的方法 pet.eat(); pet.register(); return pet; }; //(6)使用 子類(lèi)對(duì)父類(lèi)的實(shí)例化 var jim=new oneShop();//開(kāi)寵物店 var pig= jim.getpet("dog");//從寵物店得到寵物 pig.run();//寵物功能 pig.sing() })();
注:代碼中的注釋編號(hào)表示其大概思考過(guò)程及實(shí)現(xiàn)順序。
總結(jié)一下,在該個(gè)模式中主要體現(xiàn)在多態(tài)多一點(diǎn)?,F(xiàn)在我們將前面的各種綜合在一起使用JavaScript的eval()做一個(gè)智能化的工廠。
4,通過(guò)eval()實(shí)現(xiàn)智能化工廠
(1)接口文件和繼承文件的引入,如上述的一模一樣,這里將不再重復(fù)貼代碼了,直接開(kāi)始我們的新東西吧。
(2)接口調(diào)用
var Pet=new Interface("Pet",["eat","run","sing","register"]);
(3)將相同部分提取出來(lái)(簡(jiǎn)單的提?。?/p>
//基類(lèi) 分析后有共同的提出來(lái)作為基類(lèi) function basePet() { this.register=function () { document.write("寵物登記。。。。<br>"); }; this.eat=function () { document.write("寵物吃飯。。。。<br>"); } }
(4)各動(dòng)物類(lèi)
//實(shí)現(xiàn)類(lèi) 繼承基類(lèi)+接口實(shí)現(xiàn) function Dog() { Dog.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小狗跑......<br>") } this.sing=function () { document.write("小狗唱歌......<br>") } } function Cat() { Cat.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小貓跑......<br>") } this.sing=function () { document.write("小貓唱歌......<br>") } } function Pig() { Pig.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小豬跑......<br>") } this.sing=function () { document.write("小豬唱歌......<br>") } } function Bird() { Bird.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小鳥(niǎo)跑......<br>") }; this.sing=function () { document.write("小鳥(niǎo)唱歌......<br>") } }
(5)實(shí)現(xiàn)各動(dòng)物類(lèi)繼承基類(lèi)
//繼承 extend(Dog,basePet); extend(Cat,basePet); extend(Pig,basePet); extend(Bird,basePet);
(6)將商店核心抽取出來(lái),做成一個(gè)抽象類(lèi),代碼如下,
var petShop=function () {}; petShop.prototype={//模擬抽象類(lèi) 需要被子類(lèi)覆蓋 getPet:function (kind){ var pet=this.getpet(kind); pet.eat(); pet.register(); return pet; }, getpet:function (model){ throw new Error("該類(lèi)是抽象類(lèi),不能實(shí)例化") } };
//這里是做成抽象類(lèi)其中的getpet方法是通過(guò)子類(lèi)實(shí)現(xiàn)的。
(7)做一個(gè)智能工廠
//(5)智能工廠 只負(fù)責(zé)生成寵物 var PetFactory={ sellPet:function (kind) { var pet; pet=eval("new "+kind+"()"); Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)行接口Pet里面全部的方法 return pet; } }
(8)利用子類(lèi)來(lái)滿足各個(gè)商家的不同類(lèi)型寵物店的實(shí)現(xiàn) ,代碼如下
其中一個(gè)子類(lèi)
//利用子類(lèi)來(lái)滿足各個(gè)商家的不同類(lèi)型寵物店的實(shí)現(xiàn) (多態(tài)) var oneShop=function () { }; extend(oneShop,petShop);//繼承 //覆寫(xiě)方法 oneShop.prototype.getpet=function (model) { //寵物對(duì)象 var pet=null; //寵物種類(lèi) var pets=["Dog","Cat","Bird"];//商店自己擁有的寵物 寵物貨架 for(v in pets){//循環(huán)出索引 if(pets[v]==model){//model是我們自己傳遞過(guò)來(lái)需要?jiǎng)?chuàng)建的寵物 pet=PetFactory.sellPet(model); //驗(yàn)證接口 Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)行接口Pet里面全部的方法 pet.eat(); pet.register(); break; } } return pet;
另一個(gè)子類(lèi)
//(商店2)利用子類(lèi)來(lái)滿足各個(gè)商家的不同類(lèi)型寵物店的實(shí)現(xiàn) (多態(tài)) twoShop=function () {}; extend(twoShop,petShop);//商店的繼承 //覆寫(xiě)方法 twoShop.prototype.getPet=function (model) { //寵物對(duì)象 var pet=null; //寵物種類(lèi) var pets=["Pig"];//商店自己擁有的寵物 for(v in pets){//循環(huán)出索引 if(pets[v]==model){ pet=PetFactory.sellPet(model); //驗(yàn)證接口 Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)行接口Pet里面全部的方法 pet.eat(); pet.register(); break; } } return pet; };
(9)實(shí)現(xiàn)開(kāi)寵物店賣(mài)寵物
這里我們來(lái)開(kāi)第二個(gè)商店,賣(mài)Pig
var shop=new twoShop();//創(chuàng)建商店 var pet=shop.getPet("Pig");//從商店中得到寵物 pet.run();//寵物的功能
(10)智能化工廠的代碼
(function () { //(1)接口調(diào)用 var Pet=new Interface("Pet",["eat","run","sing","register"]); //(2)基類(lèi) 分析后有共同的提出來(lái)作為基類(lèi) function basePet() { this.register=function () { document.write("寵物登記。。。。<br>"); }; this.eat=function () { document.write("寵物吃飯。。。。<br>"); } } //(3)各個(gè)動(dòng)物類(lèi)(實(shí)現(xiàn)類(lèi)) 繼承基類(lèi)+接口實(shí)現(xiàn) function Dog() { Dog.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小狗跑......<br>") } this.sing=function () { document.write("小狗唱歌......<br>") } } function Cat() { Cat.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小貓跑......<br>") } this.sing=function () { document.write("小貓唱歌......<br>") } } function Pig() { Pig.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小豬跑......<br>") } this.sing=function () { document.write("小豬唱歌......<br>") } } function Bird() { Bird.superClass.constructor.call(this);//繼承父類(lèi) //實(shí)現(xiàn)接口 this.run=function () { document.write("小鳥(niǎo)跑......<br>") }; this.sing=function () { document.write("小鳥(niǎo)唱歌......<br>") } } //繼承 extend(Dog,basePet); extend(Cat,basePet); extend(Pig,basePet); extend(Bird,basePet); //(4)把核心商店抽取出來(lái) var petShop=function () {}; petShop.prototype={//模擬抽象類(lèi) 需要被子類(lèi)覆蓋 getPet:function (kind){ var pet=this.getpet(kind); pet.eat(); pet.register(); return pet; }, getpet:function (model){ throw new Error("該類(lèi)是抽象類(lèi),不能實(shí)例化") } }; //(5)智能工廠 只負(fù)責(zé)生成寵物 var PetFactory={ sellPet:function (kind) { var pet; pet=eval("new "+kind+"()"); Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)行接口Pet里面全部的方法 return pet; } } //(6)(商店1)利用子類(lèi)來(lái)滿足各個(gè)商家的不同類(lèi)型寵物店的實(shí)現(xiàn) (多態(tài)) var oneShop=function () { }; extend(oneShop,petShop);//繼承 //覆寫(xiě)方法 oneShop.prototype.getpet=function (model) { //寵物對(duì)象 var pet=null; //寵物種類(lèi) var pets=["Dog","Cat","Bird"];//商店自己擁有的寵物 寵物貨架 for(v in pets){//循環(huán)出索引 if(pets[v]==model){//model是我們自己傳遞過(guò)來(lái)需要?jiǎng)?chuàng)建的寵物 pet=PetFactory.sellPet(model); //驗(yàn)證接口 Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)行接口Pet里面全部的方法 pet.eat(); pet.register(); break; } } return pet; }; //(商店2)利用子類(lèi)來(lái)滿足各個(gè)商家的不同類(lèi)型寵物店的實(shí)現(xiàn) (多態(tài)) twoShop=function () {}; extend(twoShop,petShop);//商店的繼承 //覆寫(xiě)方法 twoShop.prototype.getPet=function (model) { //寵物對(duì)象 var pet=null; //寵物種類(lèi) var pets=["Pig"];//商店自己擁有的寵物 for(v in pets){//循環(huán)出索引 if(pets[v]==model){ pet=PetFactory.sellPet(model); //驗(yàn)證接口 Interface.ensureImplement(pet,Pet);//判斷pet對(duì)象是否全部實(shí)行接口Pet里面全部的方法 pet.eat(); pet.register(); break; } } return pet; }; //(7)開(kāi)寵物店賣(mài)寵物 var shop=new twoShop(); var pet=shop.getPet("Pig"); pet.run(); })();
總結(jié)一下,該種智能化工廠的特點(diǎn)體現(xiàn)在我們需要什么寵物店時(shí),我們可以直接通過(guò)智能化工廠創(chuàng)建。很完美。
3,工廠模式的使用場(chǎng)景
1.需要根據(jù)不同參數(shù)產(chǎn)生不同實(shí)例,這些實(shí)例有一些共性的場(chǎng)景
2.使用者只需要使用產(chǎn)品,不需要知道產(chǎn)品的創(chuàng)建細(xì)節(jié)
注意:除非是適用場(chǎng)景,否則不可濫用工廠模式,會(huì)造成代碼的復(fù)雜度。
4.簡(jiǎn)單工廠模式優(yōu)點(diǎn)
1.工廠類(lèi)集中了所有對(duì)象的創(chuàng)建,便于對(duì)象創(chuàng)建的統(tǒng)一管理
2.對(duì)象的使用者僅僅是使用產(chǎn)品,實(shí)現(xiàn)了單一職責(zé)
3.便于擴(kuò)展,如果新增了一種業(yè)務(wù),只需要增加相關(guān)的業(yè)務(wù)對(duì)象類(lèi)和工廠類(lèi)中的生產(chǎn)業(yè)務(wù)對(duì)象的方法,不需要修改其他的地方。
感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運(yùn)行工具:http://tools.jb51.net/code/HtmlJsRun測(cè)試上述代碼運(yùn)行效果。
更多關(guān)于JavaScript相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《javascript面向?qū)ο笕腴T(mén)教程》、《JavaScript錯(cuò)誤與調(diào)試技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript數(shù)學(xué)運(yùn)算用法總結(jié)》
希望本文所述對(duì)大家JavaScript程序設(shè)計(jì)有所幫助。
相關(guān)文章
js實(shí)現(xiàn)每日自動(dòng)換一張圖片的方法
這篇文章主要介紹了js實(shí)現(xiàn)每日自動(dòng)換一張圖片的方法,涉及javascript操作圖片與日期的相關(guān)技巧,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-05-05JS實(shí)現(xiàn)電影票選座的項(xiàng)目示例
電影院選座基本上每個(gè)人都用到過(guò),本文主要介紹了JS實(shí)現(xiàn)電影票選座的項(xiàng)目示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04js實(shí)現(xiàn)控制文件拖拽并獲取拖拽內(nèi)容功能
本片文章主要給大家分享了用JS寫(xiě)出控制文件拖拽并獲取拖拽內(nèi)容功能實(shí)現(xiàn)過(guò)程,以及代碼分享,有興趣的一起學(xué)習(xí)下。2018-02-02javascript 簡(jiǎn)練的幾個(gè)函數(shù)
看CSDN上別人的代碼,感覺(jué)比較精煉,拿來(lái)主義,需要的朋友可以看下。2009-08-08瀏覽器環(huán)境下JavaScript腳本加載與執(zhí)行探析之動(dòng)態(tài)腳本與Ajax腳本注入
這篇文章主要介紹了瀏覽器環(huán)境下JavaScript腳本加載與執(zhí)行探析之動(dòng)態(tài)腳本與Ajax腳本注入 的相關(guān)資料,需要的朋友可以參考下2016-01-01EL表達(dá)式截取字符串的函數(shù)說(shuō)明
這篇文章主要介紹了EL表達(dá)式截取字符串的函數(shù)說(shuō)明,在文章下面給大家介紹了JSTL中自帶的方法列表以及其描述,需要的朋友參考下吧2017-09-09實(shí)例講解JavaScript 計(jì)時(shí)事件
這篇文章主要介紹了JavaScript 計(jì)時(shí)事件的相關(guān)資料,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07輕松實(shí)現(xiàn)javascript圖片輪播特效
這篇文章主要幫助大家輕松實(shí)現(xiàn)javascript圖片輪播特效,點(diǎn)擊標(biāo)簽還可以實(shí)現(xiàn)圖片切換,感興趣的小伙伴們可以參考一下2016-01-01