瓜籽儿的Blog

专注于JavaScript技术!努力用最简单的办法去解决最复杂的问题!

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

工厂模式

Posted on 2010-03-31 23:03  瓜籽  阅读(247)  评论(0编辑  收藏  举报

    JavaScript的设计模式共有大概11种,分别是:“工厂模式”,“桥接模式”,“组合模式”,“门面模式”,“适配器模式”,“装饰者模式”,“享元模式”,“代理模式”,“观察者模式”,“命令模式”和“职责链模式”。

    不要被他们的名字给虎住,其实也没什么大不了的。有些就是根据他们的长相起的名字,这些模式都是用来帮助我们搭好一个JS骨架,以便在之后的添加或修改过程中能够更好的加以完善;而不至于像块烂肉似的往那儿一扔,等时间长了连自己都不想碰了。其实我也是块“烂肉”,哪需要就在哪儿写也就是个没有执照的江湖郎中,无非就是头痛医头,脚痛医脚没有什么章法,有时候连自己写的东西都不想看;改起来就更别说了。无意间看了一些关于JS的设计模式,感觉学到了些东西。有些时候可以拿来先使使,今天就先说说“工厂模式”,这个也是我第一个先接触到的。有些地方还不算太明白,哪儿说的不对希望各位懂行儿的牛人给指教一下。

    好了,言归正传开始我们新的旅程。

    在我们写一个JS类或是对象的过程中往往会包含别的对象。而在创建这种成员对象的时候,可能已经习惯于使用常规方式,也就是用new关键字和类构造函数。而问题也出现于此,这会导致相关的两个类之间产生依赖性。那么工厂模式就可闪亮登场了,它可以有助于消除这两个类之间的依赖性,工厂模式会使用一个方法来决定空间要实例化哪个全体的类。

    先来看一下简单工厂的例子(以自行车出售为例也是JS设计模式一书中的用例):

/* BicycleShop class */
//  这个就相当于是一个工厂
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;
	}
};

    sellBicycle方法根据所要求的自行车型号用switch语句创建一个自行车的实例。各种型号的自行车实例可以互换使用,因为它们都实现了Bicycle接口。

/* The Bicycle interface */

var Bicycle = new Interface('Bicycle', ['assemble', 'wash', 'ride', 'repair']);	//  设置Bicycle接口。设置Bicycle中要有数组中的那些方法。



/* Speedster class */
 
//  这个就相当于是一个商店,是一个从工厂里进货的小商店  
var Speedster = function(){	//  实现Bicycle接口
	// 属性或方法调用
};

Speedster.prototype = {
	assemble : function(){},
	wash : function(){},
	ride : function(){},
	repair : function()
}

    要出售某种型号的自行车,只要调用sellBicycle方法即可:

var californiaCruisers = new BicycleShop();
var youNewBike = californiaCruisers.sellBicycle('The Speedster');

    以上呢只是一个比较简单的工厂模式的例子,这个例子还不够健壮。如果要对自行车发生一些改变,如要新增加新型号的自行车那我们操作起来就会有些不便了。真正的工厂模式与简单工厂模式的区别在于,它不是另外使用一个类或对象来创建自行车,而是使用一个子类。按照正式定义,工厂是一个将其成员对象的实例化推迟到子类中进行的类。我们还以自行车为例做一个更为详细的说明。

    现在的要求是:打算让各个自行车商店自行决定从哪个生产厂家进货。出于这个原因,我们可以把BicycleShop设计为抽象类,让子类根据各自的进货渠道实现其createBicycle方法:

/* BicycleShop class (abstract) */

var BicycleShop = function(){}

BicycleShop.prototype = {
	sellBicycle : function(model){
		var bicycle = this.createBicycle(model);
		
		bicycle.assemble();
		bicycle.wash();

		return bicycle;
	},

	createBicycle : function(model){
		throw new Error('Unsupported operatioin on an abstract class.');	//  这只是一个抽象类中的接口,要在子类中实现
	}
};

    现在这只是一个抽象类还不能被实例化,只能用来派生子类。我们可以设计一个经销特定自行车生产厂家产品的子类需要扩展BicycleShop,重定义其中的createBicycle方法。以下是两个子类,其中一个是从Acme公司进货;另一个则从General Products公司进货。

    这个是从AcmeBicycle进货的商店:

/* AcmeBicycleShop class. */

var AcmeBicycleShop = function(){};

extend(AcmeBicycleShop, BicycleShop);	//  继承父类(BicycleShop)中的方法和属性

AcmeBicycleShop.prototype.createBicycle = function(model){
	var bicycle;

	switch(model){
		case 'The Speedster':
			bicycle = new Speeder();
			break;
		case 'The Lowrider':
			bicycle = new Lowrider();
			break;
		case 'The Flatlander':
			bicycle = new AcemFlatlander();
			break;
		case 'The Comfort Cruiser':
		default:
			bicycle = new AcmeComfortCruiser();
	}
	Interface.ensureImplements(bicycle, Bicycle);
	return bicycle;
};

    这个是从General Products进货的商店:

/* GeneralProductsBicycleShop class */

var GeneralProductsBicycleShop = function(){};

GeneralProductsBicycleShop.prototype.createBicycle = function(model){
	var bicycle;

	switch(model){
		case 'The Speeder':
			bicycle = new Speeder();
			break;
		case 'The Lowrider':
			bicycle = new Lowrider();
			break;
		case 'The Flatlander':
			bicycle = new GeneralProductsFlatlander();
			break;
		case 'The Comfort Cruiser':
		default:
			bicycle = new GeneralProductComfortCruiser();
	}
	Interface.ensureImplements(bicycle, Bicycle);
	return bicycle;
};

    自行车的销售工作还和以前一样,只是不同的是所开的商店是两家不现的专卖店:

var alesCruisers = new AcmeBicycleShop();
var yourNewBike = alesCruisers.sellBicycle('The Lowrider');

var bobsCruisers = new GeneralProductsBicycleShop();
var yourSencondBike = bobsCruisers.sellBicycle('The Lowrider');

    如果要增加对其他生产厂家的支持也很简单,只要再创建一个BicycleShop的子类并重定义其createBicycle工厂方法即可。当然也可以对各个子类进行修改,以支持相关厂家其他型号的产品。这是工厂模式最重要的特点。对Bicycle进行一般性操作的代码可以全部写在父类BicycleShop中,而对具体的Bicycle对象进行实例化的工作则被留到子类中。一般性的代码被集中在一个位置,而个体性的代码则被封闭在子类中。

    工厂模式适用于动态实现,节省设置开销以及用许多小对象组成一个大对象的场合。工厂模式还有许多可以用到的地方,因为我也是初次接触了解的也不是很深只是把我所得到的一点心得写了下来。对于工厂模式更加有威力有价值的地方还需要大家去慢慢地挖掘。利用工厂模式的好处是可以先创建一个抽你蝗父类,然后在创建工厂方法,从而把成员对象的实例化推迟到更专门化的子类中进行。弱化对象间的耦合防止代码的重复。万物都是相关的不可能只有好没有坏;也不会只坏不好。工厂模式亦是如此,在利用工厂模式的时候,如果根本不可能另外抵用一个类,或者不需要在运行期间在一系列可互换的类中进行选择,那就没必要使用工厂方法。大多数类最好使用new关键字和构造函数公开地进行实例化。这可以让代码更简单易读。工厂方法在其适用场合非常有用,但切勿滥用。

    以上只是个人对工厂模式的一点结节,有些地方的代码是来自与《JavaScript设计模式》中的示例。如果大家有兴趣可以买一本来看看,不算太厚应该可以看懂。