工厂模式二之真正工厂

简单工厂是将商店和工厂分开,把工厂生产的放到另外的一个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');
View Code

这里我们只要上面的代码,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');
View Code

index.html

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

<script src="factory.js"></script>
</body>
</html>
View Code

总结:

通过衣服店的例子,简单地讨论了简单工厂和真正工厂模式。简单工厂是通过另一个对象的方法或者类的实例化来完成工作。而真正工厂是把类的实现方法交给子类实例化进行的,降低对象间的耦合,消除不必要的代码执行。这种模式用于实现比较复杂的代码结构,越复杂越体现其优越性。子类的创建会让分工变得更加明细。

posted @ 2015-02-03 22:36  Songyc  阅读(294)  评论(0编辑  收藏  举报