js-Observer pattern

前言: 如有错误和遗漏,欢迎通过kencall@163.com联系我

Observer JavaScript Design Pattern

观察者模式Observer是一种设计模式,其中,一个对象,称为subject维持一系列依赖于它(观察者)的对象,将有关状态的任何变更自动通知给它们。

网上很多人将观察者模式与发布订阅模式(Publish/Subscribe)进行混淆。它们之间确实有很多相同点,但是在设计上还是有很大不同。

ok,废话不多说。看javaScript设计模式中的代码:

构建Observer的CRUD

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
function ObserverList(){
this.observerList = []
}
ObserverList.prototype.Add = function(obj) {
return this.observerList.push(obj)
}
ObserverList.prototype.Empty = function() {
this.observerList = []
}
ObserverList.prototype.Count = function() {
return this.observerList.length
}
ObserverList.prototype.Get = function(index) {
if(index > -1 && index < this.observerList.length) {
return this.observerList[index]
}
}
//新增observer的位置不是最后就是最前
ObserverList.prototype.Insert = function(obj,index) {
var pointer = -1;
if(index === 0) {
this.observerList.unshift(obj)
pointer = index;
}else if (index === this.observerList.length) {
this.observerList.push(obj)
pointer = index;
}
return pointer
}
// 找寻observer的具体索引
ObserverList.prototype.IndexOf = function(obj, startIndex) {
var i = startIndex, pointer = -1;
while(i< this.observerList.length) {
if(this.observerList[i] === obj) {
pointer = i;
}
i++
}
return pointer
}
ObserverList.prototype.RemoveIndexAt = function(index) {
if(index === 0) {
this.observerList.shift()
}else if (index === this.observerList.length-1) {
this.observerList.pop()
}else {
var reset = this.observerList.slice(index + 1);
this.observerList.length = index < 0 ? this.observerList.length + index : index;
this.observerList = this.observerList.concat(reset)
}
}

// 一个赋值方法
function extend(obj, extension) {
for(var key in obj) {
extension[key] = obj[key]
}
}

subject对observer的CRUD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 具体动作的发出者,维护者 --用于发布信息给依赖于它的观察者对象
function Subject() {
this.observers = new ObserverList;
}
Subject.prototype.AddObserver = function(observer) {
this.observers.Add(observer)
}
Subject.prototype.RemoveObserver = function(observer) {
this.observers.RemoveIndexAt(this.observers.IndexOf(observer, 0))
}
Subject.prototype.Notify = function(context) {
var observerCount = this.observers.Count()
for(var i = 0; i< observerCount; i++) {
// 这里的Update是实例方法
this.observers.Get(i).Update(context)
}
}

实际应用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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="addNewObserver">Add New observer checkbox</button>
<input id="mainCheckbox" type="checkbox" />
<div id="observersContainer"></div>
<div id="observerControl"></div>

<script src="./observer.js"></script>
<script>
var controlCheckBox = document.getElementById('mainCheckbox'),
addObserverBtn = document.getElementById('addNewObserver'),
container = document.getElementById('observerContainer')
// 这个按钮就是一个具体目标,控制发布所有信息给它的观察者
extend(new Subject(), controlCheckbox)
// 当这个具体目标点击时,会触发依赖于suject的各个观察者对象
controlCheckbox["onclick"] = new Function("controlCheckbox.Notify(controlCheckbox.checked)")
// 接下来定义多个基于suject的各个观察者
function Observer() {
this.Update = function() {
// 这里的方法一般会被重写,因为在这个例子中,this需要指向inputDOM本身才有意义,如果将check定义在这里的话,无法找到this,DOM本身
}
}
function AddNewObserver() {
var check = document.createElement('input')
check.type="checkbox"
extend(new Observer(), check)
// 上面是添加一个观察者
check.Update = function(value) {
// 同步多个observer的更新方法
this.checked = value;
}
// suject目标添加观察者
controlCheckbox.AddObserver(check)
container.appendChild(check)
}
// 这里只是为了测试--新增多个观察者
addObserverBtn["onclick"] = AddNewObserver
</script>
</body>
</html>

实际应用2

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="subject">我是具体目标</div>
<div id="observer1">我是观察者1</div>
<div id="observer2">我是观察者2</div>
<div id="observer3">我是观察者3</div>
<div id="cancalObserver">解除第二个观察者</div>
</body>
</html>
<script src="./observer.js"></script>
<script>
let subject = document.getElementById('subject'),
observer1 = document.getElementById('observer1'),
observer2 = document.getElementById('observer2'),
observer3 = document.getElementById('observer3'),
cancalObserver = document.getElementById('cancalObserver');
// 定义subject
extend(new Subject(), subject);
subject.addEventListener('click',function() {
// 触发更新机制
subject.Notify('明天放假一天')
})
// 定义observer及其回调
function Observer() {
// 这个函数的作用在于抽象,如果事件不复杂的话,也可以像下面一样,直接自定义
this.Update= function() {}
}

// 给suject添加observer
subject.AddObserver(observer1)
subject.AddObserver(observer2)
subject.AddObserver(observer3)


observer1.Update= function(acceptInfo) {
console.log(acceptInfo+'-- 好的,观察者一收到')
}
observer2.Update= function(acceptInfo) {
console.log(acceptInfo+'-- 好的,观察者二收到')
}
observer3.Update= function(acceptInfo) {
console.log(acceptInfo+'-- 好的,观察者三收到')
}

// 解除某一观察者
cancalObserver.addEventListener('click', function() {
subject.RemoveObserver(observer2),
console.log('观察者二解除观察----》》》')
})
</script>

总结

那么最后:什么是观察者模式—> :

  1. 首先要定义一个subject目标源,监听某一事件->触发subject.Notify(->触发observer.Update())
  2. 定义具体的observer,考虑事件是否可抽象->(subject发布信息后,观察者具体需要做的事情)
  3. 给subject添加具体的observer

观察者模式

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

subject触发某一事件的时候,会自动发布事件给它的观察者。这个观察者不需要监听某一事件.但是suject必须显示地添加其观察者

发布/订阅模式

In ‘Publisher-Subscriber’ pattern, senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers.

而发布者不必知道订阅者是谁,只需要将事件发布到一个“中间件”,由中间件去处理订阅者的不同需求

文章目录
  1. 1. Observer JavaScript Design Pattern
    1. 1.1. 构建Observer的CRUD
    2. 1.2. subject对observer的CRUD
    3. 1.3. 实际应用1
    4. 1.4. 实际应用2
  2. 2. 总结
    1. 2.0.1. 观察者模式
    2. 2.0.2. 发布/订阅模式
|