观察者模式 (发布订阅模式)

"Hello World, Hello Blog"

Posted by wudimingwo on December 15, 2018

封装事件模块

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
           function Event () {
              this.cache = {};
              this.onceFlag = {};
            }
            Event.prototype.on = function (type,handle) {
              if (this.cache[type]) {
                this.cache[type].push(handle);
              } else {
                this.cache[type] = [handle];
              }
            }
            Event.prototype.emmit = function (type) {
              var args = [].slice.call(arguments,1);
              var _this = this;
              this.cache[type].forEach(function (item) {
                item.apply(_this,args);//没有return ?
                if (item.onceFlag) {
                  _this.remove(type,item);
                }
              });
              
            }
            Event.prototype.remove = function (type, handle) {
             this.cache[type] = this.cache[type].filter(function (ele) {
                return handle !== ele;
              })
            }
            Event.prototype.empty = function (type) {
              this.cache[type] = [];
            }
            
            Event.prototype.once = function (type,handle) {
              handle.onceFlag = true;
              this.add(type,handle);
            }

image.png 观察者模式 我的状态改变,我就会通知你们, 代理模式 等到你状态改变,我再通知你

咦,发现代理模式和其他模式有个不一样的地方, 代理模式是有监听的, 不是目标对象状态改变后通知我, 而是我不停的监听目标对象的状态.

案例

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
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewprot" content="width=device-width, initial-scale=1.0"/>
        <meta http-equiv="X-UA-Compatible" content="ie=edge"/>
        <title>dddd</title>
        <style type="text/css">
            
        </style>
    </head>
    <body>
         
        <script type="text/javascript">
           // 封装事件模块
            function Event () {
              this.cache = {};
              this.onceFlag = {};
            }
            Event.prototype.on = function (type,handle) {
              if (this.cache[type]) {
                this.cache[type].push(handle);
              } else {
                this.cache[type] = [handle];
              }
            }
            Event.prototype.emmit = function (type) {
              var args = [].slice.call(arguments,1);
              var _this = this;
              this.cache[type].forEach(function (item) {
                item.apply(_this,args);
                if (item.onceFlag) {
                  _this.remove(type,item);
                }
              });
              
            }
            Event.prototype.remove = function (type, handle) {
              this.cache[type].filter(function (ele) {
                return handle !== ele;
              })
            }
            Event.prototype.empty = function (type) {
              this.cache[type] = [];
            }
            
            Event.prototype.once = function (type,handle) {
              handle.onceFlag = true;
              this.add(type,handle);
            }
          // 继承事件模块
            PlaneFactory.prototype = new Event();
           
           

          // 装饰者模式
            function PlaneFactory () {
              // 资源池也可以设定在子类上,让每个实例拥有不同的资源池?
              this.decorate_list = [];
            }
            // 集合所有装饰方法
            PlaneFactory.prototype.decorators = {
              eatOneLife: function (obj) {// 这就明显不是继承了,而是直接在对象上增删改查了.
              	obj.blood += 100; 
              },
              eatTwoLife: function (obj) {
              	obj.blood += 200; 
              }
            }
            // 搜集对某对象的装饰描述
            PlaneFactory.prototype.decorate = function (decorator) {
            	// 
              if(typeof this.decorators[decorator] == "function")
            	this.decorate_list.push(this.decorators[decorator]);
            }
            
            // 更新, 让装饰方法作用在该对象的身上
            PlaneFactory.prototype.update = function () {
              for (var i = 0; i < this.decorate_list.length;i++) {
                this.decorators[ this.decorate_list[i] ] && this.decorators[ this.decorate_list[i] ](this); 
              }
            }
            
            PlaneFactory.prototype.empty = function () {
            	// 清空
            	this.decorate_list = [];
            }
            PlaneFactory.prototype.remove = function (type) { 
              // 删除
            	this.decorate_list = this.decorate_list.filter(function (ele) {
            		return type !== ele
            	})
            }
            
            //子类工厂都可以使用的公共方法.
            PlaneFactory.prototype.touch = function () {
            	this.blood -= 50;
            	console.log(this.blood);
            	if (this.blood <= 0) {
            		this.die();
            	}
            	
            }
            PlaneFactory.prototype.die = function () {
            	alert('boomb');
            }
            // 创建对象的接口 // 这个接口定义在函数上,类似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 arg = [].slice.call(arguments,1);
            	var newPlane = new PlaneFactory.prototype[type](...arg);
            	// new 的时候 不好用call | apply 因为会改变this指向, 而new 是为了生成新的this 应该是有冲突..
            	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;
            }
            PlaneFactory.prototype.BigPlane = function (x, y) {
              this.x = x;
              this.y = y;
            	this.width = 150;
              this.height = 200;
              this.name = 'bigPlane';
              this.blood = 200;
            }
            PlaneFactory.prototype.AttackPlane = function (x, y) {
              this.x = x;
              this.y = y;
            	this.width = 120;
              this.height = 100;
              this.name = 'attackPlane';
              this.blood = 100;
                this.attack = function () {
                	console.log('biu');
                }
            }
            
            var oAp = PlaneFactory.create('AttackPlane',10,20);
            var oSp = PlaneFactory.create('SmallPlane',20,30);
            var oBp = PlaneFactory.create('BigPlane',40,50);
            
            
            // 装饰者模式
            oAp.decorate('eatOneLife');
            oAp.decorate('eatTwoLife');
            oAp.remove('eatOneLife');// remove 只有在 update()执行前有效果.
            oAp.update();
            console.log(oAp);
            
            
            oAp.on('over',function () {
            	this.die();
            })
            oSp.emmit('over');
            // 由于把事件模块绑定在了顶端抽象工厂上,所以事件可被所有实例所触发.
            // 解决办法是 把事件模块让每个实例 继承, 这样互不干扰
            // 又或者,增加一个维度,除了 type, 再加一个标识,用来标识 不同实例?
            
        </script>
    </body>
</html>