抄一遍:
定义: 工厂模式定义创建对象的接口, 但是让子类去真正的实例化.
也就是工厂方法将类的实例化延迟到子类.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 1. 原始模式
var plane = {
width : 100,
height : 100,
blood : 100,
touch : function () {
this.blood += 15;
if(this.blood <= 0) {
console.log('die');
}
}
}
//无法满足后续需求?
// 因为会有相似属性?
// 只要有相似,写代码的时候, 只要感觉有相似的感觉,
// 我们就可以想办法解决.
// 把所有 con+c con+v 的需求 都用某种模式搞定?
简单工厂模式
1
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
// 2. 构造函数模式 // 类
function SamllPlane () {
this.width = 100;
this.height = 100;
this.name = 'smallPlane';
this.blood = 100;
this.touch = function () {
this.blood -= 100;
if (this.blood <= 0) {
console.log('die');
}
}
}
new SmallPlane();
function BigPlane () {
this.width = 150;
this.height = 200;
this.name = 'bigPlane';
this.blood = 200;
this.touch = function () {
this.blood -= 100;
if (this.blood <= 0) {
console.log('die');
}
}
}
// 我们试着把这两种整合一下
1.工厂类集中了所有对象的创建,便于对象创建的统一管理.
2.对象的使用者仅仅是使用产品,实现了单一职责.
3.便于扩展,如果新增了一种业务,只需要增加
相关的业务对象类和工厂类中的生产业务对象的方法,
不需要修改其他的地方.
4.确实违反了开闭原则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function PlaneFactory (type) {// type = 'SmallPlane' | "BigPlane"
var newPlane = null;
switch (type){
case type:
newPlane = new SmallPlane();
break;
case type:
newPlane = new BigPlane();
break;
}
newPlane.die = function () {// 对比原始模式,这就生了一次 con+v
console.log('boomb');
}
return newPlane;
// 缺陷,生成的实例,无法访问原型, 因为 PlaneFactory 不是真正的构造函数.
// 不过在上面 BigPlane.prototype = new PlaneFactory() 似乎也能解决.
}
PlaneFactory('SamllPlane');
工厂方法模式: 不再有唯一的一个工厂类只创建产品,
而是将不同的产品交给对应的工厂子类去实现.
每个产品由负责生产的子工厂来创造.
如果添加新的产品,
需要做的就是添加新的子工厂和产品,
而不需要修改其他的工厂代码.
1.抽象工厂类: 负责定义创建产品的公共接口.
2.产品子工厂: 继承抽象工厂类,实现抽象工厂类提供的接口.
3.每一种产品有各自的产品类.
抽象工厂模式 步骤1
1
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
<script type="text/javascript">
//抽象工厂模式
function PlaneFactory () {
}
//子类工厂都可以使用的公共方法.
PlaneFactory.prototype.touch = function () {
}
// 创建对象的接口 // 这个接口定义在函数上,类似jq的工具方法.
// 如果该接口定义在原型上, 则必须实例化之后才能调用, 跟现实场景模拟不符.
PlaneFactory.create = function (type) {
// 判定是否存在该类型的子类工厂.
if (PlaneFactory.prototype[type] == undefined) {
throw 'no this constructor'
}
//实现继承 子工厂继承PlaneFactory
if (PlaneFactory.prototype[type].prototype.__proto__ !== PlaneFactory.prototype) {// 这个条件时判断有没有完成继承
// 问题? 重复继承会怎么样? 继承虽然没什么问题, 但 子工厂的 原型就会被刷新, 有可能会把在外面定义在在该原型的数据抹掉.
PlaneFactory.prototype[type].prototype = new PlaneFactory();
}
// 创建对象
var newPlane = new PlaneFactory.prototype[type]();
return newPlane;
// 子工厂可能有需要传参的情况,如果直接在这里传参,
// 逻辑可能会变得复杂,复杂度会变高, 并且调用的时候,参数太多,不太好用.
}
// 真正定义子类工厂
PlaneFactory.prototype.SmallPlane = function (x, y) {
this.x = x;
this.y = y;
this.width = 100;
this.height = 100;
this.name = 'smallPlane';
this.blood = 100;
this.touch = function () {
this.blood -= 100;
if (this.blood <= 0) {
console.log('die');
}
}
}
PlaneFactory.prototype.BigPlane = function () {
this.width = 150;
this.height = 200;
this.name = 'bigPlane';
this.blood = 200;
this.touch = function () {
this.blood -= 50;
if (this.blood <= 0) {
console.log('die');
}
}
}
PlaneFactory.prototype.AttackPlane = function () {
this.width = 120;
this.height = 100;
this.name = 'attackPlane';
this.blood = 100;
this.touch = function () {
this.blood -= 100;
if (this.blood <= 0) {
console.log('die');
}
}
this.attack = function () {
console.log('biu');
}
}
var oAp = PlaneFactory.create('AttackPlane');
</script>
1.所谓的开闭原则的一个体会. 对修改关闭,对扩展开放. 修改,一般指的是函数, 扩展,一般就是对象. 所以可以认为, 把需要修改函数的需求, 想办法调整结构,调整成对象的扩展需求. 函数里面如果添加内容,一般就是修改了吧?
2.针对上面的抽象工厂模式, 我们试着总结一下结构. 是两层构造函数, 第一层构造函数的原型上可以定义重复性强的一些属性或方法, 留出一个接口,接收一个函数名作为参数,用来调用第二层构造函数. 第二层构造函数继承第一层构造函数.
3. 不同属性的级别,可以用new 实例的时候传不同的值. 不同实例的级别,可以选择不同的子工厂,如果没有,可以添加新的工厂.
如果相似的实例,需要类似的方法,可以定义在子工厂的原型上, 如果是更普遍的方法,可以定义在,父工厂上.