您的位置:首页 > 其它

工厂模式

2016-04-23 17:19 357 查看
文中示例代码引用自《Javascript设计模式》一书

使用工厂模式的目的

消除对象间的耦合,简化更换所使用的类的工作以及简化在运行期间动态选择所用类的工作。(即弱化对象间耦合以及防止代码的重复)

工厂模式的思路

先创建出所要用到的小对象,然后生成并返回包含这些小对象的容器,即大对象。

示例

自行车商店

非工厂模式

不同自行车店,卖不同类自行车

var BicycleShop = function () { };
BicycleShop.prototype = {
sellBicycle: function (model) {
var bicycle;
switch (model) {
case 'The Speedster':
bicycle = new Speedster();
break;
case 'The Lowrider':
bicycle = new Lowrider();
break;
case 'The Comfort Cruiser':
default:
bicycle = new ComfortCruiser();
}
Interface.ensureImplements(bicycle, Bicycle);
bicycle.assemble();
bicycle.wash();
return bicycle;
}
};
无论哪家自行车店,都具有该服务,即各类自行车店都实现了该自行车接口。

var Bicycle = new Interface('Bicycle', ['assemble', 'wash', 'ride', 'repair']);
var Speedster = function () { ...};
Speedster.prototype={
assemble:function(){
...
},
wash:function(){
...
},
ride:function(){
...},
repair:function(){
...
}
};
有某种自行车,要卖掉
var californiaCruisers = new BicycleShop();
var yourNewBike = californiaCruisers.sellBicycle('The Speedster');
若现在增加了某个新的种类的自行车店,则需要对BIcycleShop这一个大类进行更改,即代码的耦合性较高,牵一发而动全身

工厂模式

经常发生变动的小对象被分离出来,生成一个函数

  var BicycleShop = function () { };
    BicycleShop.prototype = {
        sellBicycle: function (model) {
            var bicycle=this.createBicycle(model);
            bicycle.assemble();
            bicycle.wash();
            return bicycle;
        },
        createBicycle: function (model)
        {
            var bicycle;
            switch (model) {
                case 'The Speedster':
                    bicycle = new Speedster();
                    break;
                case 'The Lowrider':
                    bicycle = new Lowrider();
                    break;
                case 'The Comfort Cruiser':
                default:
                    bicycle = new ComfortCruiser();
            }
            Interface.ensureImplements(bicycle, Bicycle);
            return bicycle;
        }
    };


这样,当产生新种类自行车的商店时,我们只需要改变BicycleShop.createBicycle函数,即
BicycleShop.createBicycle=function (model)
{
var bicycle;
switch (model) {
case 'The Speedster':
bicycle = new Speedster();
break;
case 'The Lowrider':
bicycle = new Lowrider();
break;
case 'The FlatLander':
bicycle = new Flatlander();
break;
case 'The Comfort Cruiser':
default:
bicycle = new ComfortCruiser();
}
Interface.ensureImplements(bicycle, Bicycle);
return bicycle;
}

而不是改变一个BicycleShop大类,这样一来耦合性大大降低。
再比如现在除了增加不同类别自行车的店,还增加了不同进货渠道的信息,不同的进货渠道的自行车在不同的店卖,不同类别的自行车也在不同的店卖。
我们通过继承,来分别定义不同进货渠道下,不同类自行车的所在店。比如有两个进货渠道,Acme和General Products公司。
则这两个进货渠道分别继承BicycleShop这一类。

var AcmeBicycleShop = function () { };
extend(AcmeBicycleShop, BicycleShop);
AcmeBicycleShop.prototype.createBicycle = function (model) {
var bicycle;
switch (model) {
case 'The Speedster':
bicycle = new AcmeSpeedster();
break;
case 'The Lowrider':
bicycle = new AcmeLowrider();
break;
case 'The FlatLander':
bicycle = new AcmeFlatlander();
break;
case 'The Comfort Cruiser':
default:
bicycle = new AcmeComfortCruiser();
}
Interface.ensureImplements(bicycle, Bicycle);
return bicycle;
}
var GeneralProductsBicycleShop = function () { };
extend(GeneralProductsBicycleShop, BicycleShop);
GeneralProductsBicycleShop.prototype.createBicycle = function (model) {
var bicycle;
switch (model) {
case 'The Speedster':
bicycle = new GeneralProductsSpeedster();
break;
case 'The Lowrider':
bicycle = new GeneralProductsLowrider();
break;
case 'The FlatLander':
bicycle = new GeneralProductsFlatlander();
break;
case 'The Comfort Cruiser':
default:
bicycle = new GeneralProductsComfortCruiser();
}
Interface.ensureImplements(bicycle, Bicycle);
return bicycle;
}


XHR工厂的动态定义函数

var AjaxHandler = new Interface('AjaxHandler', ['request', 'createXhrObject']);
var SimpleHandler = function () {};
SimpleHandler.prototype={
request:function(method,url,callback,postVars){
var xhr=this.createXhrObject();
xhr.onreadystatechange=function(){
...
};
xhr.open(method,rul,true)
},
createXhrObject:function(){
var methods=[
function(){return new XMLHttpRequest();},
function(){return new ActiveXObject('Msxml2.XMLHTTP');},
function(){return new ActiveXObject('Microsoft.XMLHTTP');}
];
for(var i=0,len=methods.length;i<len;i++){

try{
methods[i]();
}
catch(e){
continue;
}
this.createXhrObject=methods[i]//memoize the method。
//运行过一次该位置后,实例化对象.createXhrObject就根据其首次运行的浏览器环境被指向对应的方法了
//再次执行request函数时,其调用的createXhrObject函数就是这个被赋值的函数,而不用再重新判断一遍
//即动态定义函数
return methods[i];
throw new Error('SimpleHandler:Could not create an XHR object')
}
}
}


注意,该模式并非什么时候都是合适的模式,当以下两种情况时,最好用new关键字和构造函数公开进行实例化,这样可以简化代码结构,增强代码的易读性,可以一眼就看到调用的是什么构造函数,而不用去查看某个工厂方法才能知道实例化的是什么类。

根本不可能另外换用该类
不需要在运行期间在可互换类中动态进行选择时,
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: