工厂模式一之简单工厂
工厂用来生产商品,然后卖给供应商,再由供应商转手给门店,再卖给顾客 。这样的一种生产到供应的过程,看看如何应用到我们的程序中。
1.下面以衣服店为例子。
第一步:创建衣服店类。
clothes.js
//创建一个衣服店模型。 var ClothesShop = function (){} ClothesShop.prototype = { sellClothes: function (color){ var clothesType = ['Red', 'Blue', 'Yello', 'Green', 'Gray']; var clothes; for(var i = 0, len = clothesType.length; i < len; i++) { if(color === clothesType[i]){ clothes = eval('new '+ color); //new Red(); } } //判断制造的是不是衣服。 Interface.ensureImplements(clothes, Clothes); //出售 return clothes; } } /*门店1 var clothesShop1 = new ClothesShop(); */
创建一个门店模型。按照这个模型来实例化门店对象,可以创建多个门店clothesShop1,clothesShop2, clothesShop3..每个门店都有各种漂亮颜色红蓝黄绿灰的衣服。顾客通过type决定要买什么样的衣服。假设type为'Red',通过实例化衣服类new Red()来生产红色的衣服。Interface.ensureImplements在鸭式辨型中提过。这里用来检测衣服是否实现了衣服接口(检测商品到底合不合格)。
Interface类
var Interface = function (name, methods) { if(!methods) { throw new Error('Methods is undefined.'); } if(!Array.isArray(methods)) { throw new Error('Methods is not an array.'); } this.name = name; this.methods = []; //自定义方法作为类的依据 for(var i = 0, len = methods.length; i < len; i++) { var method = methods[i]; if(typeof method !== 'string') { throw new Error('Method name expected to be a string.'); break; } this.methods.push(method); } }
ensureImplements方法
Interface.ensureImplements = function () { var canFoundMethods = []; if(arguments.length < 2) { throw new Error('Arguments is expected at least 2.'); } //取第二个参数("鸭子"的实例),称为参照对象 for(var i = 1, len = arguments.length; i < len; i++) { var interface = arguments[i]; //遍历参照对象的方法名称,对比检测对象。 for(var j = 0, methodsLength = interface.methods.length; j < methodsLength; j++) { var method = interface.methods[j]; if(!arguments[0][method] || typeof arguments[0][method] !== 'function') { //检测对象没有的方法名称则记录 canFoundMethods.push(method); } } } //最后输出没有的方法 if(canFoundMethods.length) { throw new Error ('Method ' + canFoundMethods.join(',') + ' was not found.'); } }
第二步:定义衣服接口Clothes。
//衣服接口。衣服是什么?自定义为衣服制造出来的,可以穿,可以洗,可以晒干的。 var Clothes = new Interface('Clothes', ['make', 'ware', 'wash', 'dry']);
定义一个衣服接口,并且自定义具有这四个特点的就是衣服。接口就是一个规则,用来检测对象具有某些方法的手段。
//定义红色衣服的模型。 var Red = function (){}; Red.prototype = { color: function (){return 'Red';}, make: function (){}, ware: function (){}, wash: function (){}, dry: function (){} }
定义衣服模型。按照这个模型可以生产很多红色的衣服new Red()。当然这里也可以是其它的衣服模型var Green = function (){},Green.prototype = {..};
第三步:实例化ClothesShop类,调用sellClothes方法。
//按照衣服门面店的模型,创建一个衣服店。当然也可以创建N个店,clothesShop1,clothesShop2... var clothesShop = new ClothesShop(); //指定你要的选的颜色,买新的衣服 var yourNewClothes = clothesShop.sellClothes('Red');
当clothesShop调用sellClothes方法时,就像顾客下订单,然后由店来生产衣服,检测,最后出售。简单的工厂模式完成了,可以高兴一下。但是还是存在着一点问题,这里存在clothesShop既是门店,也是生产衣服的工厂。明显不符合我们的逻辑。我们肯定想的是把工厂和门店要分开。
第四步:创建工厂对象
//===============工厂制造衣服================== //把制造工作交给工厂,商店只负责出售衣服,分工明确。 var clothesFactory = { createClothes: function (color) { var clothesType = ['Red', 'Blue', 'Yello', 'Green', 'Gray']; var clothes; for(var i = 0, len = clothesType.length; i < len; i++) { if(color === clothesType[i]){ clothes = eval('new '+ color); //new Red(); } } //判断制造的是不是衣服。 Interface.ensureImplements(clothes, Clothes); //衣服出厂 return clothes; } }
用一个名为clothesFactory的工厂对象来实现createClothes方法。这样要需要的时候就可以在sellClothes调用createClothes方法。
第五步:修改ClothesShop类
//创建一个衣服门店模型。 var ClothesShop = function (){} ClothesShop.prototype = { sellClothes: function (color){ var clothes = clothesFactory.createClothes(color); //出售 return clothes; } }
修改ClothesShop门店模型,只负责出售衣服。到这里简单工厂完成了。
完整代码:
clothes.js
1 /** 2 * Created by Song_yc on 2015/2/2. 3 */ 4 //创建一个衣服门面店模型。 5 var ClothesShop = function (){} 6 ClothesShop.prototype = { 7 sellClothes: function (color){ 8 var clothes = clothesFactory.createClothes(color); 9 //出售 10 return clothes; 11 } 12 } 13 /*门店1 14 var clothesShop1 = new ClothesShop(); 15 门店2 16 var clothesShop2 = new ClothesShop(); 17 门店3 18 var clothesShop3 = new ClothesShop();*/ 19 20 var Interface = function (name, methods) { 21 if(arguments.length !== 2) { 22 throw new Error('Interface constructor called with' + arguments.length + 'arguments, but expected exactly 2.'); 23 } 24 this.name = name; 25 this.methods = []; 26 if(!Array.isArray(methods)) { 27 throw new Error('The second argument is expected array object instance of ' + typeof method+ '.'); 28 } 29 for(var i = 0, len = methods.length; i < len; i++) { 30 var method = methods[i]; 31 if(typeof method !== 'string') { 32 throw new Error('Interface constructor expects method names to be as a string.'); 33 break; 34 } 35 this.methods.push(method); 36 } 37 } 38 39 Interface.ensureImplements = function () { 40 var canFoundMethods = []; 41 //First to determine argument's length. 42 if(arguments.length < 2) { 43 throw new Error('Arguments is expected at least 2.'); 44 } 45 //Second to determine instance class. 46 for(var i = 1, len = arguments.length; i < len; i++) { 47 var interface = arguments[i]; 48 if(interface.constructor !== Interface) { 49 throw new Error(interface.name + 'object is not instanced of Interface Class.'); 50 } 51 for(var j = 0, methodsLength = interface.methods.length; j < methodsLength; j++) { 52 var method = interface.methods[j]; 53 if(!arguments[0][method] || typeof arguments[0][method] !== 'function') { 54 //throw new Error('Method ' + method + 'was not found.'); 55 canFoundMethods.push(method); 56 } 57 } 58 } 59 //canFoundMethods.forEach(function (methodName) { 60 // throw new Error('Method ' + methodName + 'was not found.'); 61 //}) 62 if(canFoundMethods.length) { 63 throw new Error ('Method ' + canFoundMethods.join(',') + ' was not found.'); 64 } 65 } 66 //定义衣服类。衣服是什么?被制造出来的,可以穿,可以洗,可以晒干的。 67 var Clothes = new Interface('Clothes', ['make', 'ware', 'wash', 'dry']); 68 //定义红色衣服的模型。 69 var Red = function (){}; 70 Red.prototype = { 71 color: function (){return 'red';}, 72 make: function (){}, 73 ware: function (){}, 74 wash: function (){}, 75 dry: function (){} 76 } 77 78 //===============工厂制造衣服================== 79 80 //把制造工作交给工厂,商店只负责出售衣服,分工明确。 81 var clothesFactory = { 82 createClothes: function (color) { 83 var clothesType = ['Red', 'Blue', 'Yello', 'Green', 'Gray']; 84 var clothes; 85 for(var i = 0, len = clothesType.length; i < len; i++) { 86 if(color === clothesType[i]){ 87 clothes = eval('new '+ color); //new Red(); 88 } 89 } 90 //判断制造的是不是衣服。 91 Interface.ensureImplements(clothes, Clothes); 92 //衣服出厂 93 return clothes; 94 } 95 } 96 97 //按照衣服门面店的模型,创建一个衣服店。当然也可以创建N个店,clothes1,clothes2... 98 var clothesShop = new ClothesShop(); 99 //选择喜欢的颜色 100 var yourNewClothes = clothesShop.sellClothes('Red');
index.html
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <script src="clothes.js"></script> </body> </html>
最后看看新的衣服。
2.总结:
回顾一下:首先创建一个门店模型,拥有生产各色衣服的方法。然后定义衣服接口,创建红色衣服模型,通过接口检测衣服是否合格。实例化门店,门店按照顾客的喜好进行生产衣服,检测,出售。最后把门店生产独立设计成简单工厂,生产和门店分离。
- 简单工厂方法就是把创建类实例的方法放在外部对象,当实例化对象时在外部对象中进行。