观察者模式的基本概念:目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口。具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,调度观察者的更新方法。
观察者模式
是不是看着糊里糊涂的,一般人不太喜欢看太过专业的术语来理解文本内容,那我们就通俗的说一下
- 观察者模式故名思意就是观察,
我自己
去看着某个东西的某种变化,举个例子,我
看着我正在炸的面丸子
,看是否熟了,那这里我自己
就是观察者,面丸子
就是被观察者,那么大家是不是可以同时观察,我爸妈
都过来了,都在看着这个正在炸的面丸子
,那么现在,我``我爸``我妈
都是观察者,面丸子
还是被观察者,那么反过来想,我可不可以观察多个东西,当然,我如果类比机器,精力无限,我
是可以看着很多的东西的,我看着正在炸的面丸子
,还看着手机的微信
,看是否有人给我发消息,同时观察了两个东西,是完全可以的 - 观察者模式有一个很重要的概念,就是,观察者是一个整体,当观察者去给目标添加观察的时候,是把自身注册进去的,当目标触发固定的变化之后,也是目标去调用观察者自身固定的方法,有人问那我可不可以目标发生不同变化的时候去根据注册进来的观察者的不同调用不同的方法,可以,加一些判断嘛
- 第二段话也可以举一个例子,就是我看着炸丸子,是我本身在看着,当丸子熟了,丸子就会指使我做一些事情,重要的就是,指使,而不是把接下来的事情告诉丸子让丸子自己去做,简单来说就是
我
这个对象,自己去调用自己的方法 - 为什么要说这么多的观察者模式的概念呢,是因为观察者模式很容易跟发布订阅者模式混淆,我们说完观察者模式会在下边说发布订阅者模式并梳理不同之处,或者说观察者模式内部就是基于发布订阅者模式来实现的
//引用别人的代码,我自己就不改了
//被观察者类(被观察的目标)
class Subject{
constructor(){
this.subs = [];
}
addSub(sub){
this.subs.push(sub);
}
notify(){
this.subs.forEach(sub=> {
sub.update();
});
}
}
//观察者类
class Observer{
update(){
console.log('update');
}
}
两者是创造观察者和被观察者的类
//创建一个观察者和一个目标(被观察者)
et subject = new Subject();
let ob = new Observer();
//目标添加观察者了
subject.addSub(ob);
//目标通过了某种逻辑触发了更改或者其他状态
if(...){
//目标的方法调用,观看商法代码可以发现,目标一个个的通知了或者调用了观察者的方法
subject.notify();
}
重点就是,观察者把自身添加在了目标的身上,只需等待逻辑触发,目标就会调用这些观察者的方法
优点:完全没有耦合关系,观察者和被观察虽然是传递进入自身,但是其实是没有任何的必须关系,也可以是另一个观察者被传入,可以是任何观察者把自身传入,只要符合逻辑即可
缺点就是每个观察者自身都得有目标以及固定的要调用的方法,但是观察者除此之外是完全自由的
发布订阅者模式
发布订阅者模式与观察者模式表面看着比较一致,但是实际不同,发布订阅者模式有一个中转的地方,叫调度中心,调度中心使这种模式常用于通信中间件等地方,但是调度中心也添加了发布订阅者的耦合性
简单来说就是有一个经纪人,我去找经纪人给我买车,经纪人就把我登记在他的册子上了,经纪人就开始关注哪个卖车人发布了卖车的消息,有人要卖车,就会通知我,区别就是这里的我并不是一直在那里守着,而是留了一个电话号码,那经纪人就是通过这个电话号码来联系我
- 网上代码
var pubsub = (()=>{
var topics = {};
function subscribe(topic,fn){
if(!topics[topic]){
topics[topic] = [];
}
topics[topic].push(fn);
}
function publish(topic,...args){
if(!topics[topic])
return;
for(let fn of topics[topic]){
fn(...args);
}
}
return {
subscribe,
publish
}
})()
pubsub.subscribe('test',functionA);//订阅者A订阅了test事件
pubsub.subscribe('test',functionB);//订阅者B订阅了test事件
pubsub.publish('test','123','HH'); //123 HH(发布者B发布了test事件)
我们来分析这段代码,重点核心就是pubsub方法,这个就是所谓的经纪人,经纪人很有能力,可以记载订阅人所订阅的事件,也可以区分事件来通过电话号码通知外部,电话号码就是functionA和functionB
每一个订阅者传递的事件(手机号码)都会被储存起来,当发布者发布消息的时候,就会遍历相应的储存的订阅事件方法去调用,也就是一个个的拨打电话
- 很像吧,和观察者模式很像,但是区别就是一个是自己在等着观察着,一个是留了电话号码,看起来是不是观察者模式更机智一些,但是实际上这样会导致有一个方法一直被固定在那里,松耦合但是依然存在耦合,优点也更明显,逻辑更加清晰,代码虽然多了一点但是却更加简单,事实就是这样,越是封装度轻的代码越是多,但是却越是简单越是使用广泛,毕竟我们只是需要一个这样的思想