作用:
观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状 态发生改变时,所有依赖于它的对象都将得到通知。
栗子:
假如我们正在开发一个商城网站,网站里有 header 头部、nav 导航、消息列表、购物车等模块。这几个模块的渲染有一个共同的前提条件,就是必须先用 ajax 异步请求获取用户的登录信息。这是很正常的,比如用户的名字和头像要显示在 header模块里,而这两个字段都来自用户登录后返回的信息。
如果它们和用户信息模块产生了强耦合,比如下面这样的形式:
login.succ(function(data){
header.setAvatar( data.avatar); // 设置 header 模块的头像
nav.setAvatar( data.avatar ); // 设置导航模块的头像
});
至于 ajax 请求什么时候能成功的返回用户信息,这点我们没有办法确定。所以使用事件通知机制去处理(观察者模式)
// 观察者
function Observer(){
this.state = null;
this.arr = [];
}
Observer.prototype.attach = function(s){
this.arr.push(s);
}
Observer.prototype.setState = function(newState){
this.state = newState;
this.arr.forEach(s=>s.update(this.state));
}
// 被观察者
function Subject(name){
this.name = name;
}
Subject.prototype.setAvatar = function (data) {
console.log(`设置 ${this.name} 模块的头像`)
}
Subject.prototype.update = function(newState){
this.setAvatar(newState.avatar)
}
let o = new Observer();
let s1 = new Subject('nav');
let s2 = new Subject('header');
o.attach(s1);
o.attach(s2);
o.setState({avatar: '数据'});
总结:
1.观察者模式的优点非常明显,一为时间上的解耦,二为对象之间的解耦。它的应用非常 广泛,既可以用在异步编程中,也可以帮助我们完成更松耦合的代码编写。
2.观察者模式也不是完全没有缺点。创建订阅者本身要消耗一定的时间和内存,而且当你订阅一个消息后,也许此消息最后都未发生,但这个订阅者会始终存在于内存中。
3.观察者模式虽然可以弱化对象之间的联系,但如果过度使用的话,对象和对象之间的必要联系也将被深埋在背后,会导致程序难以跟踪维护和理解。特别是有多个发布者和订阅者嵌套到一起的时候,要跟踪一个 bug不是件轻松的事情。