JavaScript设计模式:工厂模式(附接口模式代码)

工厂模式目的:消除类之间的依赖性。
在引入工厂模式以前,我们先给出接口类的代码:

var Interface = function(name,methods){
    if(arguments.length != 2){
        throw new Error("expect 2 arguments.");
    }

    this.name = name;
    this.methods = [];
    if(!methods instanceof Array){
        throw new Error("expect the second argument be an Array.");
    }else{
        methods.forEach(function(method){
            if(typeof method != "String"){
                throw new Error("expect the second argument be an Array of String.");
            }
            this.methods.push(method);
        });
    }
}

Interface.ensureInplements = function(object){
    if(arguments.length < 2){
        throw new Error("expect 2 or more arguments.");
    }

    for(var i = 1, len = arguments.length ; i<len ; i++){
        var interface = arguments[i];
        if(interface.constructor != Interface){
            throw new Error("the arguments must be instances of Interface");
        }
        for(var j=0,methodsLen=interface.methods.length;j<methodsLen;j++){
            var methods = interface.methods[j];
            if(!object[methods] || typeof object[methods] !== "function"){
                throw new Error("methods was not found.");
            }
        }
    }
}

接口类就是为了保证某些对象一定都具有某些方法,可以用Interface.ensureInplements验证。例如,我们想验证car对象是不是Car接口的实例,可以这样写:

Interface.ensureInplements(car,Car);

Car接口可以通过new Interface(“Car”,[“drive”,”ring”…]);这样的形式定义其必须的方法。
这样在通过了Interface.ensureInplements(car,Car);方法后,我们就能保证car对象也拥有方法drive,ring…

简单工厂

直接上栗子比较好:比如说,你想开一家花店,出售各种鲜花:

var FlowerShop = function(){};
FlowerShop.prototype.sellFlowers = function(name){
    var flower;
    switch(name){
        case 'rose':
            flower = new Rose();
            break;
        case 'lily':
            flower = new Lily();
            break;
        default:
            flower = new NormalFlower();
    }
    Interface.ensureInplements(flower,Flower);
    flower.watering();
    flower.prune();
    return flower;
}
// Flower Interface
var Flower = new Interface("Flower",["watering","prune"...]);

这样,如果我们想要玫瑰花,就:

var newFlowerShop = new FlowerShop();
var rose = newFlowerShop.sellFlowers("rose");

但是,如果你想要为你的花店新加入一种花呢?你就要改写FlowerShop类,即便是这个类的基本功能其实并没有改变:创建鲜花,把花洗干净,修剪,然后返回给客户。

更好的方式是把创建鲜花实例这部分代码交给一个工厂对象。

var FlowerFactory = {
    createFlower : function(name){
        var flower;
        switch(name){
            case 'rose':
                flower = new Rose();
                break;
            case 'lily':
                flower = new Lily();
                break;
            default:
                flower = new NormalFlower();
        }
        Interface.ensureInplements(flower,Flower);
        return flower;
    }
}

FlowerFactory这个对象可以作为一个单体,用来把createFlower方法封装在一个命名空间中,这个方法返回的flower对象实现了Flower接口。这样,我们的花店代码就可以改为:

var FlowerShop = function(){};
FlowerShop.prototype.sellFlowers = function(name){
    var flower = FlowerFactory.createFlower("rose");
    flower.watering();
    flower.prune();
    return flower;
}

工厂模式

真正的工厂模式和简单的工厂模式的区别在于,它不是另外使用一个类,而是使用一个子类来实现对象的创建。
工厂模式的正式定义是:将其成员对象的实例化推迟到子类来实现的类。也就是说,前面的FlowerShop应该作为一个抽象类,真正的实现需要其子类来完成。比如,我们可以创建一个北京花店,出售各种花,也可以再创建一个上海花店,等等。具体对花的实例化代码应该在子类(例如北京花店)中完成。

对FlowerShop的一般性操作应该写在FlowerShop中,而其他个性的代码则被分配到子类中。


版权声明:本文为u014328357原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。