工厂模式又可以分为:简单工厂、工厂方法、抽象工厂。
简单工厂模式:又叫静态工厂方法,由一个工厂对象决定创建某一种产品对象类的实例。主要用来创建同一类对象。
实例1:比如我们玩游戏的时候,通常会有多种角色,每个角色又有自己的技能。
var Warrior = function () {
this.name = '战士'
this.skill = ['刺杀', '十字斩']
}
Warrior.prototype = {
work: function () {
console.log('work')
},
ko: function () {
console.log('ko 战士')
}
}
var Master = function () {
this.name = '法师'
this.skill = ['雷电术', '保护盾']
}
Master.prototype = {
work: function () {
console.log('work')
},
getMan: function () {
console,log('getMan')
}
}
var Warlock = function () {
this.name = '道士'
this.skill = ['火符', '召唤神兽']
}
Warlock.prototype = {
work: function () {
console.log('work')
}
}
// 下面这个函数就是工厂方法
var RoleFactory = function (role) {
switch (role) {
case '战士':
return new Warrior();
case '法师':
return new Master();
case '道士':
return new Warlock();
default:
throw new Error('参数错误。。。');
}
}
var solider = RoleFactory('法师');
console.log(solider.name)
solider.work()
solider.getMan()
这样我们就实现了简单工厂。我们不需要记住工厂内的所有基类是如何实现的,只需要把我们想要的角色传进工厂方法中就能创建出那个角色的实例对象供我们使用。
上面的简单工厂中我们看到有许多相似的地方,我们可以想到把相似的东西提取,不相似的针对性处理。我们创建一个对象,然后对这个对象进行方法和属性的扩展,最终把这个对象返回出来即可。
var RoleFactory = function (role) {
var obj = {}
// 相同部分
obj.name = role;
obj.work = function () {
console.log('work')
}
if (role == '战士') {
// 差异部分
obj.skill = ['刺杀', '十字斩']
obj.ko = function () {
console.log('ko 战士')
}
} else if (role == '法师') {
// 差异部分
obj.skill = ['雷电术', '保护盾']
obj.getMan = function () {
console,log('getMan')
}
} else if (role == '道士') {
// 差异部分
obj.skill = ['火符', '召唤神兽']
}
return obj;
}
var solider = RoleFactory('法师');
console.log(solider.name)
solider.work()
solider.getMan()
这两个工厂模式还是有一些区别,第一种是通过类来实例对象创建,第二种是通过创建新的对象来包装属性和方法实现的。
他们之间的差异性也造成前面通过类创建的对象,如果这些类继承同一父类,那么他们的父类原型上的方法是可以共用的。而后面创建新对象的方式都是一个新的个体,他们的方法就不能共用了。
工厂方法模式的本意就是将实际创建对象的工作推迟到子类中,所以我们可以将工厂方法看作是一个实例化对象的工厂类。
在简单工厂模式的第一种方案中,我们添加一个角色就要修改两处代码(需要新增角色构造函数,还要在工厂中新增个角色判断)。
所以我们把简单工厂模式的第一种方案变为工厂方法模式。安全起见,我们采用安全模式类,我们将创建对象的基类放在工厂方法类的原型中。
安全模式类主要解决用户不知道这个类是不是类,例如:我们知道类前面都是需要用new关键字,如果用户在使用的时候忽略了new关键字直接执行类,此时我们得到的并不是我们预期的对象(而是undefined)。
var RoleFactory = function (role) {
// 判断执行过程中this是否是当前这个对象(如果是则说明是用new创建的)
if (this instanceof RoleFactory) {
return new this[role]()
} else { // 否则重新创建这个对象
return new RoleFactory(role)
}
}
RoleFactory.prototype = {
Warrior: function () {
this.name = '战士'
this.skill = ['刺杀', '十字斩']
this.work = function () {
console.log('work')
}
this.ko = function () {
console.log('ko 战士')
}
},
Master: function () {
this.name = '法师'
this.skill = ['雷电术', '保护盾']
this.work = function () {
console.log('work')
}
this.getMan = function () {
console,log('getMan')
}
},
Warlock: function () {
this.name = '道士'
this.skill = ['火符', '召唤神兽']
this.work = function () {
console.log('work')
}
}
}
var solider = RoleFactory('Master');
console.log(solider.name)
solider.work()
solider.getMan()
这样我们解决了添加一个角色需要修改两处代码,现在我们添加一个角色只需要在RoleFactory.prototype中添加即可。
RoleFactory.prototype = {
// ...
Archer: function () {
this.name = '弓箭手'
this.skill = ['百里穿杨', '万箭齐发']
}
}
var solider = RoleFactory('Archer');
具体参考:https://blog.csdn.net/k491022087/article/details/88389763
极力推荐阅读一本书:JavaScript设计模式 张容铭