工厂模式二之真正工厂
简单工厂是将商店和工厂分开,把工厂生产的放到另外的一个clothesFactory对象中调用createClothes方法进行。这一节我们要实现真正的工厂。
回顾一下简单工厂的实现:
1 //创建一个衣服门面店模型。 2 var ClothesShop = function (){} 3 ClothesShop.prototype = { 4 sellClothes: function (color){ 5 var clothes = clothesFactory.createClothes(color); 6 //出售 7 return clothes; 8 } 9 } 10 11 var Interface = function (name, methods) { 12 if(arguments.length !== 2) { 13 throw new Error('Interface constructor called with' + arguments.length + 'arguments, but expected exactly 2.'); 14 } 15 this.name = name; 16 this.methods = []; 17 if(!Array.isArray(methods)) { 18 throw new Error('The second argument is expected array object instance of ' + typeof method+ '.'); 19 } 20 for(var i = 0, len = methods.length; i < len; i++) { 21 var method = methods[i]; 22 if(typeof method !== 'string') { 23 throw new Error('Interface constructor expects method names to be as a string.'); 24 break; 25 } 26 this.methods.push(method); 27 } 28 } 29 30 Interface.ensureImplements = function () { 31 var canFoundMethods = []; 32 //First to determine argument's length. 33 if(arguments.length < 2) { 34 throw new Error('Arguments is expected at least 2.'); 35 } 36 //Second to determine instance class. 37 for(var i = 1, len = arguments.length; i < len; i++) { 38 var interface = arguments[i]; 39 if(interface.constructor !== Interface) { 40 throw new Error(interface.name + 'object is not instanced of Interface Class.'); 41 } 42 for(var j = 0, methodsLength = interface.methods.length; j < methodsLength; j++) { 43 var method = interface.methods[j]; 44 if(!arguments[0][method] || typeof arguments[0][method] !== 'function') { 45 //throw new Error('Method ' + method + 'was not found.'); 46 canFoundMethods.push(method); 47 } 48 } 49 } 50 //canFoundMethods.forEach(function (methodName) { 51 // throw new Error('Method ' + methodName + 'was not found.'); 52 //}) 53 if(canFoundMethods.length) { 54 throw new Error ('Method ' + canFoundMethods.join(',') + ' was not found.'); 55 } 56 } 57 //定义衣服类。衣服是什么?被制造出来的,可以穿,可以洗,可以晒干的。 58 var Clothes = new Interface('Clothes', ['make', 'ware', 'wash', 'dry']); 59 //定义红色衣服的模型。 60 var Red = function (){}; 61 Red.prototype = { 62 color: function (){return 'red';}, 63 make: function (){}, 64 ware: function (){}, 65 wash: function (){}, 66 dry: function (){} 67 } 68 69 //===============工厂制造衣服================== 70 71 //把制造工作交给工厂,商店只负责出售衣服,分工明确。 72 var clothesFactory = { 73 createClothes: function (color) { 74 var clothesType = ['Red', 'Blue', 'Yello', 'Green', 'Gray']; 75 var clothes; 76 for(var i = 0, len = clothesType.length; i < len; i++) { 77 if(color === clothesType[i]){ 78 clothes = eval('new '+ color); //new Red(); 79 } 80 } 81 //判断制造的是不是衣服。 82 Interface.ensureImplements(clothes, Clothes); 83 //衣服出厂 84 return clothes; 85 } 86 } 87 88 //按照衣服门面店的模型,创建一个衣服店。当然也可以创建N个店,clothes1,clothes2... 89 var clothesShop = new ClothesShop(); 90 //选择喜欢的颜色 91 var yourNewClothes = clothesShop.sellClothes('Red');
这里我们只要上面的代码,clothesFactory工厂对象不要了。
//创建一个衣服门面店模型。 var ClothesShop = function (){} ClothesShop.prototype = { sellClothes: function (color){ var clothes = clothesFactory.createClothes(color); //出售 return clothes; } } var Interface = function (name, methods) { if(arguments.length !== 2) { throw new Error('Interface constructor called with' + arguments.length + 'arguments, but expected exactly 2.'); } this.name = name; this.methods = []; if(!Array.isArray(methods)) { throw new Error('The second argument is expected array object instance of ' + typeof method+ '.'); } for(var i = 0, len = methods.length; i < len; i++) { var method = methods[i]; if(typeof method !== 'string') { throw new Error('Interface constructor expects method names to be as a string.'); break; } this.methods.push(method); } } Interface.ensureImplements = function () { var canFoundMethods = []; //First to determine argument's length. if(arguments.length < 2) { throw new Error('Arguments is expected at least 2.'); } //Second to determine instance class. for(var i = 1, len = arguments.length; i < len; i++) { var interface = arguments[i]; if(interface.constructor !== Interface) { throw new Error(interface.name + 'object is not instanced of Interface Class.'); } 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') { //throw new Error('Method ' + method + 'was not found.'); canFoundMethods.push(method); } } } //canFoundMethods.forEach(function (methodName) { // throw new Error('Method ' + methodName + 'was not found.'); //}) if(canFoundMethods.length) { throw new Error ('Method ' + canFoundMethods.join(',') + ' was not found.'); } } //定义衣服类。衣服是什么?被制造出来的,可以穿,可以洗,可以晒干的。 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 (){} }
现实生活的衣服店大多数不是专卖店,它经营的商品可来自几个不同的供应商,我们称为杂牌店,杂牌店里可能看到张三供应商,李四供应商的。衣服的来源五花八门,所以这里就不再是单一的clothesFactory对象生产的,用this代替。
ClothesShop.prototype = { sellClothes: function (color){ var clothes = this.createClothes(color); //出售 return clothes; } }
供应商类
var zhangshanClothesShop = function (){}; extend(zhangshanClothesShop, ClothesShop);
创建张三供应商类zhangshanClothesShop, 供应商类继承了门店类。于是子类拥有了父类的方法。因为门店进货也有自已的标准啊,不是什么货都随便要的。供应商生产的衣服要按照门店的要求生产。所以要继承它的方法。
extend函数
function extend(subClass, superClass){ var F = function () {}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; }
最后供应商生产
zhangshanClothesShop.prototype.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; }
供应商类zhangshanClothesShop通过实例化,调用createClothes方法就可以生产clothes。
var zhangshanClothesshop = new zhangshanClothesShop(); var yourNewClothes = zhangshanClothesshop.sellClothes('Red');
如果全部由zhangshanClothessshop调用createClothes,那么我们的门店就是一家专卖店,张三衣服专卖店。在实例化Blue之前,还要创建Blue类。
var Blue = function (){}; Blue.prototype = { color: function (){return 'blue';}, make: function (){}, ware: function (){}, wash: function (){}, dry: function (){} }
var yourNewClothes = zhangshanClothesshop.sellClothes('Red'); var yourNewClothes2 = zhangshanClothesshop.sellClothes('Blue'); //var yourNewClothes3 = zhangshanClothesshop.sellClothes('Yellow'); //var yourNewClothes4 = zhangshanClothesshop.sellClothes('Green'); //var yourNewClothes5 = zhangshanClothesshop.sellClothes('Gray');
我们想要多个品牌的衣服,那就要从不同的供应商进货。只要创建多个供应商类就可以了。
//李四 var lisiClothesShop = function (){}; extend(lisiClothesShop, ClothesShop); lisiClothesShop.prototype.createClothes = function (color){ var clothesType = ['Red', 'Blue', 'Yellow', '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; } var lisiClothesshop = new lisiClothesShop(); var myNewClothes = lisiClothesshop.sellClothes('Red');
虽然myNewClothes和yourNewClothes同样是衣服对象,都是红色的衣服,都具有相同的方法make,ware,wash等,只是出自于不同的供应商或者说是不同的工厂生产的。这就是唯一的区别。工厂模式是用子类通过类继承(extend方法),拥有父类的方法。再通过实例化子类对象,调用父类方法来实现父类要完成的工作。这样做是为了降低类与类的耦合,似乎把一个人的工作分给两个人来做,变得轻松和灵活。
完整代码:
factory.js
1 //创建一个衣服门面店模型。 2 var ClothesShop = function (){} 3 ClothesShop.prototype = { 4 sellClothes: function (color){ 5 var clothes = this.createClothes(color); 6 //出售 7 return clothes; 8 } 9 } 10 11 var Interface = function (name, methods) { 12 if(arguments.length !== 2) { 13 throw new Error('Interface constructor called with' + arguments.length + 'arguments, but expected exactly 2.'); 14 } 15 this.name = name; 16 this.methods = []; 17 if(!Array.isArray(methods)) { 18 throw new Error('The second argument is expected array object instance of ' + typeof method+ '.'); 19 } 20 for(var i = 0, len = methods.length; i < len; i++) { 21 var method = methods[i]; 22 if(typeof method !== 'string') { 23 throw new Error('Interface constructor expects method names to be as a string.'); 24 break; 25 } 26 this.methods.push(method); 27 } 28 } 29 30 Interface.ensureImplements = function () { 31 var canFoundMethods = []; 32 //First to determine argument's length. 33 if(arguments.length < 2) { 34 throw new Error('Arguments is expected at least 2.'); 35 } 36 //Second to determine instance class. 37 for(var i = 1, len = arguments.length; i < len; i++) { 38 var interface = arguments[i]; 39 if(interface.constructor !== Interface) { 40 throw new Error(interface.name + 'object is not instanced of Interface Class.'); 41 } 42 for(var j = 0, methodsLength = interface.methods.length; j < methodsLength; j++) { 43 var method = interface.methods[j]; 44 if(!arguments[0][method] || typeof arguments[0][method] !== 'function') { 45 //throw new Error('Method ' + method + 'was not found.'); 46 canFoundMethods.push(method); 47 } 48 } 49 } 50 //canFoundMethods.forEach(function (methodName) { 51 // throw new Error('Method ' + methodName + 'was not found.'); 52 //}) 53 if(canFoundMethods.length) { 54 throw new Error ('Method ' + canFoundMethods.join(',') + ' was not found.'); 55 } 56 } 57 //定义衣服类。衣服是什么?被制造出来的,可以穿,可以洗,可以晒干的。 58 var Clothes = new Interface('Clothes', ['make', 'ware', 'wash', 'dry']); 59 //定义红色衣服的模型。 60 var Red = function (){}; 61 Red.prototype = { 62 color: function (){return 'red';}, 63 make: function (){}, 64 ware: function (){}, 65 wash: function (){}, 66 dry: function (){} 67 } 68 69 var Blue = function (){}; 70 Blue.prototype = { 71 color: function (){return 'blue';}, 72 make: function (){}, 73 ware: function (){}, 74 wash: function (){}, 75 dry: function (){} 76 } 77 78 function extend(subClass, superClass){ 79 var F = function () {}; 80 F.prototype = superClass.prototype; 81 subClass.prototype = new F(); 82 subClass.prototype.constructor = subClass; 83 } 84 85 //张三类 86 var zhangshanClothesShop = function (){}; 87 //张三类供应商按照商店要求模型生产自行车模型。 88 extend(zhangshanClothesShop, ClothesShop); 89 90 zhangshanClothesShop.prototype.createClothes = function (color){ 91 var clothesType = ['Red', 'Blue', 'Yellow', 'Green', 'Gray']; 92 var clothes; 93 for(var i = 0, len = clothesType.length; i < len; i++) { 94 if(color === clothesType[i]){ 95 clothes = eval('new '+ color); //new Red(); 96 } 97 } 98 //检测。 99 Interface.ensureImplements(clothes, Clothes); 100 //衣服出厂 101 return clothes; 102 } 103 //按照衣服门面店的模型,创建一个衣服店。当然也可以创建N个店,clothes1,clothes2... 104 var zhangshanClothesshop = new zhangshanClothesShop(); 105 //选择喜欢的颜色 106 var yourNewClothes = zhangshanClothesshop.sellClothes('Red'); 107 var yourNewClothes2 = zhangshanClothesshop.sellClothes('Blue'); 108 //var yourNewClothes3 = zhangshanClothesshop.sellClothes('Yellow'); 109 //var yourNewClothes4 = zhangshanClothesshop.sellClothes('Green'); 110 //var yourNewClothes5 = zhangshanClothesshop.sellClothes('Gray'); 111 112 113 //李四 114 var lisiClothesShop = function (){}; 115 extend(lisiClothesShop, ClothesShop); 116 117 lisiClothesShop.prototype.createClothes = function (color){ 118 var clothesType = ['Red', 'Blue', 'Yellow', 'Green', 'Gray']; 119 var clothes; 120 for(var i = 0, len = clothesType.length; i < len; i++) { 121 if(color === clothesType[i]){ 122 clothes = eval('new '+ color); //new Red(); 123 } 124 } 125 //检测。 126 Interface.ensureImplements(clothes, Clothes); 127 //衣服出厂 128 return clothes; 129 } 130 var lisiClothesshop = new lisiClothesShop(); 131 var myNewClothes = lisiClothesshop.sellClothes('Red');
index.html
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <script src="factory.js"></script> </body> </html>
总结:
通过衣服店的例子,简单地讨论了简单工厂和真正工厂模式。简单工厂是通过另一个对象的方法或者类的实例化来完成工作。而真正工厂是把类的实现方法交给子类实例化进行的,降低对象间的耦合,消除不必要的代码执行。这种模式用于实现比较复杂的代码结构,越复杂越体现其优越性。子类的创建会让分工变得更加明细。