工厂模式
# 工厂模式
概念 工厂模式是用来创建对象的一种最常用的设计模式(创建性)我们不暴露创建对象的具体逻辑,而是将逻辑封装在一个函数中,那么这个函数就可以被看作一个工厂
分类 工厂模式根据抽象程度又分为三种:简单工厂模式、工厂方法模式和抽象工厂模式
# 简单工厂模式
简单工厂模式又叫 静态方法模式
因为工厂类中定义了一个静态方法用于创建对象。简单工厂让使用者不用知道具体的参数就可以创建出所需的 ”产品“ 类,即使用者可以直接消费产品而不需要知道产品的具体生产细节。
# ES5 代码实现
function Role(options) {
this.role = options.role;
this.permissions = options.permissions;
}
Role.prototype.show = function() {
var str = "是一个" + this.role + ", 权限:" + this.permissions.join(", ");
console.log(str);
};
function simpleFactory(role) {
switch (role) {
case "admin":
return new Role({
role: "管理员",
permissions: [
"设置",
"删除",
"新增",
"创建",
"开发",
"推送",
"提问",
"评论",
],
});
break;
case "developer":
return new Role({
role: "开发者",
permissions: ["开发", "推送", "提问", "评论"],
});
break;
default:
throw new Error("参数只能为 admin 或 developer");
}
}
// 实例
const xm = simpleFactory("admin");
xm.show();
const xh = simpleFactory("developer");
xh.show();
const xl = simpleFactory("guest");
xl.show();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# ES6 代码实现
class SimpleFactory {
constructor(opt) {
this.role = opt.role;
this.permissions = opt.permissions;
}
// 静态方法
static create(role) {
switch (role) {
case "admin":
return new SimpleFactory({
role: "管理员",
permissions: [
"设置",
"删除",
"新增",
"创建",
"开发",
"推送",
"提问",
"评论",
],
});
break;
case "developer":
return new SimpleFactory({
role: "开发者",
permissions: ["开发", "推送", "提问", "评论"],
});
break;
default:
throw new Error("参数只能为 admin 或 developer");
}
}
show() {
const str = `是一个${this.role}, 权限:${this.permissions.join(", ")}`;
console.log(str);
}
}
// 实例
const xm = SampleFactory.create("admin");
xm.show();
const xh = SampleFactory.create("developer");
xh.show();
const xl = SampleFactory.create("guest");
xl.show();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 简单工厂函数适用场景
正确传参,就可以获取所需要的对象,无需知道内部实现细节;
内部逻辑(工厂函数)通过传入参数判断实例化还是使用哪些类;
创建对象数量少(稳定),对象的创建逻辑不复杂;
# 简单工厂函数不适用场景
当需要添加新的类时,就需要修改工厂方法,这违背了开放封闭原则(OCP, 对扩展开放、对源码修改封闭)。正所谓成也萧何败也萧何。函数 create 内包含了所有创建对象(构造函数)的判断逻辑代码,如果要增加新的构造函数还需要修改函数 create(判断逻辑代码),当可选参数 role 变得更多时,那函数 create 的判断逻辑代码就变得臃肿起来,难以维护。
不适用创建多类对象;
# 工厂方法模式
工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫多态工厂(Polymorphic Factory)模式,它属于类创建型模式。
将实际创建对象工作推迟到子类当中,核心类就成了抽象类。这样添加新的类时就无需修改工厂方法,只需要将子类注册进工厂方法的原型对象中即可。
# 安全模式类
安全模式就是麻烦自己,方便他人的利他主义模式
可以屏蔽使用类的错误造成的错误
function Factory() {
if (!(this instanceof Factory)) {
return new Factory();
}
}
Factory.prototype.show = function() {
console.log("factory show");
};
var f = new Factory();
f.show();
2
3
4
5
6
7
8
9
10
# ES5 实现
ES5 没有像传统创建类的方式那样创建抽象类,所以工厂方法模式只需参考其核心思想即可。可将工厂方法看做一个实例化对象工厂类(采用安全模式类),将创建对象的基类放在工厂方法类的原型中即可。当需要添加新类时,只需挂载在 FunctionFactory.prototype 上,无需修改工厂方法,也实现了 OCP 原则。
// 0.0.2/es5.function.factory.js
function FunctionFactory(role) {
if (!(["admin", "developer"].indexOf(role) > -1)) {
throw new Error("参数只能为 admin 或 developer");
}
// 安全的工厂方法
if (this instanceof FunctionFactory) {
return this[role]();
}
return new FunctionFactory(role);
}
FunctionFactory.prototype.show = function() {
var str = "是一个" + this.role + ", 权限:" + this.permissions.join(", ");
console.log(str);
};
FunctionFactory.prototype.admin = function(permissions) {
this.role = "管理员";
this.permissions = [
"设置",
"删除",
"新增",
"创建",
"开发",
"推送",
"提问",
"评论",
];
};
FunctionFactory.prototype.developer = function(permissions) {
this.role = "开发者";
this.permissions = ["开发", "推送", "提问", "评论"];
};
var xm = FunctionFactory("admin");
xm.show();
var xh = new FunctionFactory("developer");
xh.show();
var xl = new FunctionFactory("guest");
xl.show();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# ES6 实现
由于 ES6 中还没有 abstract,就用 new.target 来模拟出抽象类(new.target 指向被 new 执行的构造函数),判断 new.target 是否指向了抽象类,如果是就报错。
class FunctionFactoryBase {
// 抽象类
constructor(role) {
if (new.target === FunctionFactoryBase) {
throw new Error("抽象类不能实例");
}
this.role = role;
}
}
class FunctionFactory extends FunctionFactoryBase {
// 子类
constructor(role) {
super(role);
}
static create(role) {
switch (role) {
case "admin":
return new FunctionFactory({
role: "管理员",
permissions: [
"设置",
"删除",
"新增",
"创建",
"开发",
"推送",
"提问",
"评论",
],
});
break;
case "developer":
return new FunctionFactory({
role: "开发者",
permissions: ["开发", "推送", "提问", "评论"],
});
break;
default:
throw new Error("参数只能为 admin 或 developer");
}
}
show() {
const { role, permissions } = this.role;
const str = `是一个${role}, 权限:${permissions.join(", ")}`;
console.log(str);
}
}
// let xl = new FunctionFactoryBase(); // 此行会报错,注释后方可正常执行后面
let xm = FunctionFactory.create("admin");
xm.show();
let xh = FunctionFactory.create("developer");
xh.show();
let xl = FunctionFactory.create("guest");
xl.show();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# 抽象工厂模式
抽象工厂只留对外的口子,不做事,留给外界覆盖(子类重写接口方法以便创建的时候指定自己的对象类型)。主要用于对产品类簇的创建,不直接生成实例(简单工厂模式和工厂方法模式都是生成实例)。
抽象类是一种声明但不能使用的类,子类必须先实现其方法才能调用;
可以在抽象类中定义一套规范,供子类去继承实现;
# 代码实现
// 抽象工厂
function AbstractFactory(subType, superType) {
if (typeof AbstractFactory[superType] === "function") {
//缓存类
function F() {}
//继承父类属性和方法
F.prototype = new AbstractFactory[superType]();
//将子类 constructor 指向子类(自己)
subType.prototype.constructor = subType;
//子类原型继承缓存类(父类)
subType.prototype = new F();
} else {
//不存在该抽象类抛出错误
throw new Error("抽象类不存在");
}
}
// 抽象类
AbstractFactory.Phone = function() {
this.type = "Phone";
};
AbstractFactory.Phone.prototype = {
showType: function() {
return new Error("Phone 抽象方法 showType 不能调用");
},
showPrice: function() {
return new Error("Phone 抽象方法 showPrice 不能调用");
},
showColor: function() {
return new Error("Phone 抽象方法 showColor 不能调用");
},
};
AbstractFactory.Pad = function() {
this.type = "Pad";
};
AbstractFactory.Pad.prototype = {
showType: function() {
return new Error("Pad 抽象方法 showType 不能调用");
},
showPrice: function() {
return new Error("Pad 抽象方法 showPrice 不能调用");
},
showColor: function() {
return new Error("Pad 抽象方法 showColor 不能调用");
},
};
// 抽象工厂实现对抽象类的继承
function Iphone(type, price, color) {
this.type = type;
this.price = price;
this.color = color;
}
//抽象工厂实现对 Phone 抽象类的继承
AbstractFactory(Iphone, "Phone");
Iphone.prototype.showType = function() {
return this.type;
};
Iphone.prototype.showPrice = function() {
return this.price;
};
Iphone.prototype.showColor = function() {
return this.color;
};
function Ipad(type, price, color) {
this.type = type;
this.price = price;
this.color = color;
}
AbstractFactory(Ipad, "Pad");
Ipad.prototype.showType = function() {
return this.type;
};
Ipad.prototype.showPrice = function() {
return this.price;
};
Ipad.prototype.showColor = function() {
return this.color;
};
// 实例
var iphone5s = new Iphone("iphone 5s", 3000, "白色");
console.log(
"今天刚买了" +
iphone5s.showType() +
",价格是" +
iphone5s.showPrice() +
"," +
iphone5s.showColor()
);
var iphone8s = new Iphone("iphone 8s", 8000, "白色");
console.log(
"今天刚买了" +
iphone8s.showType() +
",价格是" +
iphone8s.showPrice() +
"," +
iphone8s.showColor()
);
var ipad = new Ipad("ipad air", 2000, "骚红色");
console.log(
"今天刚买了" +
ipad.showType() +
",价格是" +
ipad.showPrice() +
"," +
ipad.showColor()
);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# 工厂模式区别
简单工厂 : 使用一个工厂对象用来生产同一等级结构中的任意产品。(不支持拓展增加产品)
工厂方法 : 使用多个工厂对象用来生产同一等级结构中对应的固定产品。(支持拓展增加产品)
抽象工厂 : 使用多个工厂对象用来生产不同产品族的全部产品。(不支持拓展增加产品;支持增加产品族)
# 工厂模式实例
- jQuery 源码-工厂模式
参考:https://juejin.cn/post/6844903895546724366 (opens new window)