观察者模式主要由一个目标对象(Subject)和一系列观察者(Observer)组成,如果目标对象发生改变,目标就会通知对应的观察者,每个观察者接收到通知后做出自己的变化。一个目标对象(Subject)可以管理自己的观察者(Observer),并且具有通知的方法,下面我们用代码来实现。
// 观察者列表,可以对观察者进行增加,修改等操作
// Subject会用到ObserverList来管理观察者
function ObserverList() {
this.observerList = [];
}
ObserverList.prototype.Add = function(obj){
// body...
return this.observerList.push(obj);
};
ObserverList.prototype.Empty = function(){
// body...
this.observerList = [];
};
ObserverList.prototype.Count = function(){
// body...
return this.observerList.length;
};
ObserverList.prototype.Get = function(index){
// body...
if(index > -1 && index < this.observerList.length) {
return this.observerList[index]
}
};
ObserverList.prototype.Insert = function(obj , index){
// body...
var pointer = -1;
if(index === 0) {
this.observerList.unshift(obj);
}
if(index === this.observerList.length) {
this.observerList.push(obj);
}
pointer = index;
this.observerList.splice(index,0,obj);
return pointer;
};
ObserverList.prototype.IndexOf = function(obj, startIndex){
// body...
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){
// body...
if( index === 0 ) {
this.observerList.shift()
}
if( index === this.observerList.length ) {
this.observerList.pop()
}
this.observerList.splice(index,1);
};
目标对象利用ObserverList来管理观察者,并具有通知的方法
//目标
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 = observerCount - 1; i >= 0; i--) {
// 收到通知后调用观察者的Update方法
this.observers.Get(i).Update(context)
}
};
观察者具有一个Update方法,每个观察者根据自己的业务来重写Update方法,
function Observer() {
this.Update = function() {
console.log('默认实现')
}
}
最后实现一个extend方法,来扩展对象
// 扩展obj对象
function extend(extension, obj) {
for(var key in extension) {
obj[key] = extension[key];
}
}
这样,观察者模式就实现了,下面我们用实际的例子来说明一下观察者模式的用法。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!-- 按钮,每次点击会增加一个checkbox,每个checkbox都是一个观察者(Observer) -->
<button id="addNewObserver"> Add New Observer checkbox</button>
<!-- 目标对象Subject,每次点击后会把checked的值用通知发出去 -->
<input type="checkbox" id="mainCheckbox">
<!-- 容器,新增的checkbox会放在该容器中 -->
<div id="observerContainer"></div>
<script>
// 引用DOM
var controlCheckbox = document.getElementById('mainCheckbox');
var addButton = document.getElementById('addNewObserver');
var container = document.getElementById('observerContainer');
// 具体目标
// 利用目标扩展 controlCheckbox
extend(controlCheckbox, new Subject() );
// 点击checkbox会触发通知到观察者
// 在Subject添加点击事件,点击后会将checked的值通知出去
controlCheckbox.addEventListener('click', new Function("controlCheckbox.Notify(controlCheckbox.checked)"))
// 添加观察者按钮点击事件
addButton.addEventListener('click', addNewObserver);
// 具体观察者
function addNewObserver() {
//创建需要添加的checkbox
var check = document.createElement("input");
check.type = 'checkbox';
// 将新增的checkbox变为一个观察者
extend(check, new Observer());
// 重写Update方法
check.Update = function (value) {
check.checked = value;
}
// subject将observer加入队列
controlCheckbox.AddObserver(check);
// 将dom加到容器中
container.appendChild(check)
}
</script>
</body>
</html>
运行后的效果大家可以自己去尝试一下,新增的checkBox的勾选状态会和第一个checkBox,也就是Subject保持一致。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。