观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。
//发布订阅模式的代码
var observer = {
//订阅(订阅功能)
addSubscriber:function(callback){
this.subscribers.push(callback);//
},
//退订(功能)
removeSubscriber:function(callback){
let index = this.subscribers.indexOf(callback);
this.splice(index,1);
},
//发布
publish:function(what){
for(let i in this.subscribers){
if(typeof this.subscribers[i]==='function'){
this.subscribers[i](what);
}
}
},
//让某个对象具备发布订阅功能
make:function(obj){
for(let key in this){
obj[key] = this[key];
}
obj.subscribers=[];
}
}
模拟vue数据绑定功能
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
</style>
</head>
<body>
请输入一个数:<input id="num" type="text" /><br/>
平方:<input id="sqrtnum" type="text" /><br/>
立方:<input id="cubenum" type="text" /><br/>
四次方:<input id="fourFangnum" type="text" /><br/>
</body>
</html>
<script type="text/javascript">
window.onload = function(){
//定义一个JavaScript对象(具有发布订阅功能的对象)
let numObj ={
};
observer.make(numObj);
//1、订阅一个平方 功能
numObj.addSubscriber(function(num){
$("#sqrtnum").value = num*num;
});
//2、订阅一个立方 功能
numObj.addSubscriber(function(num){
$("#cubenum").value = num*num*num;
});
//3、订阅一个四方 功能
numObj.addSubscriber(function(num){
$("#fourFangnum").value = num*num*num*num;
});
//3、在文本框的内容发送变化时,进行发布。
$("#num").oninput = function(){
numObj.publish(this.value);
}
}
</script>
何时使用
1.当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化,那么就可以选用观察者模式,将这两者封装成观察者和目标对象,当目标对象变化的时候,依赖于它的观察者对象也会发生相应的变化。这样就把抽象模型的这两个方面分离开了,使得他们可以独立地改变和复用。
2.如果在更改一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有多少对象需要被连带改变,这种情况可以选用观察者模式,被更改的哪一个对象很明显就相当于是目标对象,而需要连带修改的多个其他对象,就作为多个观察者对象了。
3.当一个对象必须通知其他对象,但是你又希望这个对象和其他被它统治的对象是松散耦合的。这个对象相当于是目标对象,而被它通知的对象就是观察者对象了。
优点:
- 支持简单的广播通信,自动通知所有已经订阅过的对象。
- 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。
- 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。
缺点:
- 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
- 如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致崩溃。在使用观察者模式是要特别注意这一点。
- 如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。
- 虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。