观察者模式
-
例子:监控
=> 我们坐在教室就是 被观察者
=> 监控后面的老师,就是观察者
=> 当被观察者触发了一些条件,观察者就会触发技能 -
观察者模式:监控一个对象的状态,一旦状态发生变化,马上触发技能
=> 需要两个构造函数来实现
- 创建被观察者
- 属性,自己的状态
- 队列,记录都有谁观察着自己,数组[]
- 方法:设置自己的状态,当我们需要改变的时候,要触发这个方法改变状态
- 方法:添加观察者
- 方法:删除观察者
- 创建观察者
- 需要一个身份证明
- 需要一个技能
// 观察者模式
// 定义一个观察者
class Observer {
constructor (name,fn=()=>{}){
this.name = name;
this.fn = fn;
}
}
// 创建两个观察者
const observer1 = new Observer('班主任',(state)=>{
console.log(`因为:${state}把你爸找来`);
});
const observer2 = new Observer('校长',(state)=>{
console.log(`因为:${state}骂你的班主任`);
});
console.log(observer1,observer2);
// 定义一个被观察者
class Subject {
constructor (state){
// 记录自己的状态
this.state = state;
// 用来保存观察着我的人
this.observers = [];
}
// 设置状态
setState (state){
this.state = state;
// 就需要把 我的所有观察着都通知一下
this.notify()
}
// 添加观察者
addObserver (observer){
const res = this.observers.some(item=>item.name === observer.name);
if(res) return
this.observers.push(observer);
}
// 删除观察者
removeObserver (observer){
this.observers = this.observers.filter(item=>item.name!==observer.name);
}
// 通知观察者
notify (){
//告诉他们我的状态变了
this.observers.forEach(item=>item.fn(this.state));
}
}
const xiaoming = new Subject('学习');
// 给小明添加一个观察者
xiaoming.addObserver(observer1);
xiaoming.addObserver(observer2);
console.log('xiaoming: ', xiaoming);
xiaoming.setState('学习不好');
发布订阅模式
- 有一个对象,有人一直看着他
- 当这个对象发生变化的时候,第三方通知这个看着的人,触发技能
- 例子:买书
- 普通程序员买书
- 去书店,问,没有,回家
- 过一会儿再去,问,没有,回家
- 过一会儿,问,没有,回家
- 发布订阅的程序员
- 去书店,问,没有,留下一个联系方式给店员
- 一旦有了书,就会接到电话
- 触发技能去买书
- 只需要创建一个构造函数
- 创造一个第三方店员的身份
- 我们的任务就是模拟一个 addEvntListener()
- 分析构造函数
- 属性:消息队列 { click:[fn1,fn2], abc:[fb1,fn2,fn3] }
- 方法:向消息队列里面添加内容
- 方法:删除消息队列里面的的内容
- 方法:触发消息队列里面的内容
// 发布订阅模式
// 创建一个三方观察者构造函数
class Observer {
constructor (){
this.message = {}
}
// 1. 向消息队列里面添加内容
on(type,fn){
// type 我拜托你看着的行为
// fn 我拜托你在行为发生的时候,告诉你干什么
// 判断消息队列里面是否有这个消息
if(!this.message[type]){
this.message[type] = [];
}
this.message[type].push(fn);
}
// 2. 删除消息队列里面的内容
off(type,fn){
// 判断消息队列里面是否有这个消息
if(!this.message[type]) return;
// 判断消息队列里面是否有这个函数
if(!fn){
this.message[type] = [];
}else{
this.message[type] = this.message[type].filter(item=>item!==fn);
}
}
// 3. 触发消息队列里面的内容
trigger(type){
// 判断消息队列里面是否有这个消息
if(!this.message[type]) return;
// 触发消息队列里面的内容
this.message[type].forEach(item=>item());
}
}
// 使用构造函数创建一个实例
const person1 = new Observer();
// 当你想拜托这个person1 帮你观察一些内容的时候
// 告诉你一个行为,当行为出现的时候,告诉你干什么
person1.on('abc',handlerA)
// 告诉person1,这个事情不用你管了
// 1. 我只告诉你这个事情不用你管
// person1.off('abc'); 把消息队列 里面属于a的数组清空掉
// person1.off('abc',handlerA)
person1.trigger('abc',9)
console.log('person1: ', person1);
function handlerA(){
console.log('handlerA');
}
总结
观察者模式和发布订阅者模式两个有类似之处也有不同之处,在圈内有说是同一种的也有认为不是一种的,但这都是不是我们要学习的重点,我们学习的重点时了解他们模式的内容,去理解这种实现逻辑的方式并用于项目中。
vue中有用过this.Bus.emit('xxx'),uni中用过 uni.$on('a',(xx)=>{})、uni.$emit('a',xx),这就是利用发布订阅模式实现的,可以理解uni就在内部创造第三方观察者构造函数,用于注册和监听。发布订阅者模式和观察者模式的主要区别如下图:
观察者模式:是由具体目标调度,比如当事件触发,Dep就会去调用观察者的方法,所以观察者模式得到订阅者与发布者之前的存在是依赖的
发布/订阅模式由统一调度中心调用,因此发布者和订阅者不需要知道对方的存在