观察者和发布订阅者两种模式老是容易搞混,所以单独拆开来讲一下。
一、观察者模式
// 目标对象
class TargetObj{
constructor(name){
this.targetList = []
}
/*
* 添加
* @targetObj 实例化观察者后的对象
*/
addOb(targetObj){
this.targetList.push(targetObj)
}
// 通知
notice(){
this.targetList.forEach((item)=>{
item.update(); // 调用观察者里面的修改方法表明被观察了
})
}
}
// 观察者
class Observer{
constructor(name){
this.name = name;
}
// 修改
update(){
console.log('update 我是'+ this.name);
}
}
// 实例化目标对象
let targetObj = new TargetObj()
// 实例化观察者
let o1 = new Observer('张三');
let o2 = new Observer('李四');
// 将观察者放到目标对象中
targetObj.addOb(o1);
targetObj.addOb(o2);
// 提示观察者发生改变
targetObj.notice();
// 输出 update 我是张三 update 我是李四
如上实例:在实例化一个目标对象,两个观察者后,将观察者放到目标对象中,即相当于监听了这两个观察者的动态,目标对象发生变化后,所有的观察者就会得到通知。
1:定义
观察者模式包含观察目标(Subject)
和观察者(Object)
两类对象。
1.一个目标可以有任意数目且与之相依赖的观察者。
2. 一旦观察目标发生改变,所有观察者都将得到通知。
2:优点
目标与观察者功能耦合度降低,专注自生逻辑即可;
观察者被动接受更新,实时接受目标者更新状态
3:缺点
观察者模式虽然实现了对象依赖关系的低耦合,但不能对事件通知进行细分。
4:例子
vue2的双向绑定就是通过object.defineProperty来实现的。在Vue实例被创建时,会把属性加入object.defineProperty,系统负责监听变化和订阅依赖,然后在属性变化时通过get/set方法通知组件里面的属性更新。
5:作用
当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,解决了主体对象与观察者之间功能的耦合,即一个对象状态改变给其他对象通知的问题。
二、发布订阅模式
1.定义
订阅者把订阅的事件注册到调度中心,当该事件触发时候,发布者发布该事件到调度中心,由调度中心统一调度订阅者注册到调度中心的处理代码。
2.作用
观察者和目标要相互知道,发布者和订阅者不用相互知道,通过中央调控(第三方),是观察者模式解耦后的方式。
3.例子
// 调度中心
const PubSub = {
list:[],
// 发布方法
publish(){
this.list.forEach(item => {
item();
});
},
// 订阅方法
sbuscribe(data){
this.list.push(data);
}
}
// 具体的订阅目标(订阅者)
function userA(){
console.log('userA');
}
function userB(){
console.log('userB');
}
function userC(){
console.log('userC');
}
PubSub.sbuscribe(userA);
PubSub.sbuscribe(userB);
PubSub.sbuscribe(userC);
PubSub.publish();
// 输出 userA userB userC
如上代码所示:调度中心有发布方法(publish)和订阅方法(sbuscribe),当订阅者在调度中心中调用了订阅方法,那么当使用发布方法的时候,订阅者就会得到通知触发订阅目标的行为。
三.总结
这两种模式都存在订阅者和发布者(观察者可认为是订阅者、目标可认为是发布者),但是观察者模式是由具体目标调度的,而发布/订阅模式是统一由调度中心调的,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会
。同时这两种模式都可以用于松散耦合,改进代码管理和潜在的复用。