林秀栋的技术博客

设计模式(二) 工厂模式

简单工厂模式

//用工厂判断创建哪个对象,主要用于同一类对象的创建

var a = function(){}
var b = function(){}
var c = function(){}
var k = function(name){	//工厂
	switch(name){
		case 'a':
			return new a();
		case 'b':
			return new b();
		case 'c':
			return new c();
	}
}
var k1 = k('a')

//如果几个对象中有很多相同之处的话,可以提出来,用下面的方法
//下面的方法和寄生继承很像,不同的是没有继承上面方法
function aa(name){
	var o = new Object()	//创建一个对象,并扩展其属性和功能
	o.a = 1;
	o.show = function(){};
	//上面是相同的属性功能,下面的根据name不同的
	if(name === 'a'){
		//...
	}else if(name === 'b'){
		//...
	}
	return o;
}
var kk1 = aa('a')

//上面两种方法前者通过实例化对象创建,第二个通过对新对象的包装增强属性功能
//前者如果这些类继承同一父类,那么父类原型的方法是可以共用的
//而后者寄生方式创建的对象都是新个体,方法不能共用

工厂方法模式

//通过对类的抽象使创建业务主要用于创建多类产品的实例
//简单工厂模式有个问题,当类多时,每次都需要修改两处(增加新的类,以及case里增加)
//为解决这个问题,可以:
var f = function(type, content){
	if(this instanceof f){	//安全的工厂方法,防止忘记写new
		var s = new this[type](content)
		return s
	}else{
		return new f(type, content)
	}
}
f.prototype = {
	a: function(content){},
	b: function(content){}
}
//这样每次添加只要在原型中添加一个类即可
//比如这里就是new出构造函数a
var k = new f('a', 1);

抽象工厂模式

//抽象类
var car = function(){};
car.prototype = {
	getPrice: function(){
		return new Error('抽象方法不能调用');
	}
}
//创建了一个没有任何属性,原型方法不能调用的类,但在继承上却有用。继承时一些方法需要子类重写,若子类没有重写,就会从父类继承,这时在父类抛出错误可以让我们知道忘记了重写。


//抽象类中定义的方法只是显示的定义了些功能,没有具体实现,不能用来创建真实的对象,一般用来作为父类创建子类。
var vf = function(a, b){
	//判断抽象工厂中是否有该抽象类
	if(typeof vf[b] === 'function'){
		function F(){};	//缓存类
		F.prototype = new vf[b]();	//继承父类的属性和方法
		a.constructor = a;	//将子类的constructor指向子类
		a.prototype = new F();	//子类原型继承'父类'
	}else{
		throw new Error('未创建该抽象类');	//不存在该抽象类抛出错误
	}
}
//抽象类
vf.a = function(){
	this.type = 'a';
}
vf.a.prototype = {
	aaa: function(){
		return new Error('抽象方法不可调用');
	}
}
vf.b = function(){
	this.type = 'b';
}
vf.b.prototype = {
	bbb: function(){
		return new Error('抽象方法不可调用');
	}
}
//创建子类abc
var abc = function(price){
	this.price = price;
}
vf(abc, 'a');	//实现对a抽象类的继承
abc.prototype.aaa = function(){};
var x = new abc();
//创建子类abc2
var abc2 = function(price){
	this.price = price;
}
vf(abc2, 'b');	//实现对b抽象类的继承
abc2.prototype.bbb = function(){};
var x2 = new abc2();
//抽象工厂其实是一个类似子类继承父类的方法,在抽象工厂中判断抽象类是否存在,存在则继承父类的方法
//对过渡类的原型继承时不仅需要继承父类原型的方法,还要继承父类的对象属性,所以需要new将父类构造函数执行一遍来复制其中的属性和方法
//用这种方法就知道子类属于哪个产品簇,比如这里abc属于a,abc2属于b,之后还有abc3、abc4的话也可以知道属于a还是b,同时也就知道了对应的该产品簇需要的方法并正确使用

上面的继承方法,两次new abc()时,会出现引用类型相互影响的情况。

找网上的抽象工厂模式,都是用上面的继承方法,为了不造成影响,应该使用寄生组合式继承。