工厂模式目的:消除类之间的依赖性。
在引入工厂模式以前,我们先给出接口类的代码:
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中,而其他个性的代码则被分配到子类中。