前言:
现时大家对“js订阅者模式和观察者模式”大概比较着重,朋友们都需要了解一些“js订阅者模式和观察者模式”的相关知识。那么小编在网上收集了一些关于“js订阅者模式和观察者模式””的相关文章,希望咱们能喜欢,同学们一起来了解一下吧!#头条创作挑战赛#
介绍
观察者模式中通常有两个模型,一个观察者(observer)和一个被观察者(Observed)。从字面意思上理解,即被观察者发生某些行为或者变化时,会通知观察者,观察者根据此行为或者变化做出处理。那么具体如何操作呢,接下来我们就用JavaScript代码实现一个下图所示的观察者模式。
实现观察者模式JS实现
let observer_ids=0;let observed_ids=0;//观察者类class Observer { constructor() { this.id = observer_ids++; } //观测到变化后的处理 update(ob){ console.log("观察者" + this.id + `-检测到被观察者${ob.id}变化`); }}//被观察者列class Observed { constructor() { this.observers = []; this.id=observed_ids++; } //添加观察者 addObserver(observer) { this.observers.push(observer); } //删除观察者 removeObserver(observer) { this.observers = this.observers.filter(o => { return o.id != observer.id; }); } //通知所有的观察者 notify() { this.observers.forEach(observer => { observer.update(this); }); }}let mObserved=new Observed();let mObserver1=new Observer();let mObserver2=new Observer();mObserved.addObserver(mObserver1);mObserved.addObserver(mObserver2);mObserved.notify();
输出结果为
观察者0-检测到被观察者0变化
观察者1-检测到被观察者0变化
我们把执行代码修改,添加删除观察者的代码,
let mObserved=new Observed();let mObserver1=new Observer();let mObserver2=new Observer();let mObserver3=new Observer();mObserved.addObserver(mObserver1);mObserved.addObserver(mObserver2);mObserved.addObserver(mObserver3);mObserved.removeObserver(mObserver2);mObserved.notify();
输出结果为
观察者0-检测到被观察者0变化
观察者2-检测到被观察者0变化
扩展
我们可以不直接使用上面的两个类,而是把观察者和被观察者这两个类作为基类供其他类实现。
class Teacher extends Observer{ constructor(name){ super(); this.name=name; } update(st){ // super.update(st); console.log(st.name+`提交了${this.name}作业`); }}class Student extends Observed{ constructor(name){ super(); this.name=name; } submitHomeWork(){ this.notify(this) }}let teacher1=new Teacher("数学");let teacher2=new Teacher("语文");let stu1=new Student("小玲");let stu2=new Student("小明");let stu3=new Student("小李");stu1.addObserver(teacher1);stu1.addObserver(teacher2);stu2.addObserver(teacher1);stu2.addObserver(teacher2);stu3.addObserver(teacher1);stu3.addObserver(teacher2);stu1.submitHomeWork();stu2.submitHomeWork();stu3.submitHomeWork();复制代码
上述代码的输出结果为
小玲提交了数学作业
小玲提交了语文作业
小明提交了数学作业
小明提交了语文作业
小李提交了数学作业
小李提交了语文作业
发布订阅者模式
观察者模式通常也被称为发布/订阅模式,这时候被观察者作为发布者,观察者被称为订阅者。这个也很容易理解,我们以订阅微信公众号为例。我可以订阅很多个微信公众号,这时候我是订阅者,而微信公众号为发布者,当有微信公众号发布新的文章,公众号平台会通知我,接到通知就可以去阅读新文章了。
注意:上面关于发布订阅者模式的描述并不正确,下面进行更正。
发布订阅者模式与观察者模式类似,但是两者并不完全相同,发布订阅者模式与观察者相比多了一个中间层的调度中心,用来对发布者发布的信息进行处理再发布到订阅者,大致过程如下图所示。
那么问题来了,为什么要加一个中间层的调度中心呢?通过上面对观察者模式的实现,我们的observed类中是持有observer对象的,因此并没有实现两个类的完全解耦。通过添加中间层的调度中心类,我么可以将订阅者和发布者完全解耦,两者不再有直接的关联,而是通过调度中心关联起来。下面我们继续实现一个发布订阅者模式。
//发布者class Pub{ constructor(dispatcher){ this.dispatcher=dispatcher; this.id=observed_ids++; } /** * @description: 发布方法 * @param {type} 通知类型 */ publish(type){ this.dispatcher.publish(type,this) }}//订阅者class Subscriber{ constructor(dispatcher){ this.dispatcher=dispatcher; this.id=observer_ids++; } subscribe(type){ this.dispatcher.subscribe(type,this); } doUpdate(type,arg){ console.log("接受到消息"+arg) }}//调度中心class Dispatcher{ constructor(){ this.dispatcher={}; } //订阅 subscribe(pub,subscriber){ if(!this.dispatcher[pub.id]){ this.dispatcher[pub.id]=[]; } this.dispatcher[pub.id].push(subscriber); } //退订 unsubscribe(pub, subscriber) { let subscribers = this.dispatcher[type]; if (!subscribers || !subscribers.length) return; this.dispatcher[type] = subscribers.filter(item =>{ return item.id !== subscriber.id }); } //发布 publish(type, args) { let subscribers = this.dispatcher[type]; if (!subscribers || !subscribers.length) return; subscribers.forEach(subscriber=>{ subscriber.doUpdate(type,args); }); }}class Reader extends Subscriber{ constructor(name,dispatcher){ super(dispatcher); this.name=name; } doUpdate(type,st){ // super.update(st); console.log(this.name+`阅读了--${type}--公众号的文章`); }}class WeiX extends Pub{ constructor(name,dispatcher){ super(dispatcher); this.name=name; } publishArticle(type){ this.publish(type) }}let dispatcher=new Dispatcher();//公众号let wei1=new WeiX("前端",dispatcher);let wei2=new WeiX("数据库",dispatcher);//读者们let reader1=new Reader("小玲",dispatcher);let reader2=new Reader("小明",dispatcher);let reader3=new Reader("小李",dispatcher);//读者订阅公众号reader1.subscribe("前端");reader2.subscribe("数据库");reader3.subscribe("数据库");//公众号发布文章wei1.publishArticle("前端");wei1.publishArticle("数据库");
运行结果如下:
小玲阅读了--前端--公众号的文章
小明阅读了--数据库--公众号的文章
小李阅读了--数据库--公众号的文章
通过上面的代码我们的确实现了一个简单的发布订阅模式,但是我们发现Pub类好像并不必要,因为这个类实际上只是单纯的调用了调度中心Dispatcher的publish方法。因此我们可以对上述代码进行简化。
let ids=0;let observer_ids=0;//订阅者class Subscriber{ constructor(dispatcher){ this.dispatcher=dispatcher; this.id=observer_ids++; } subscribe(type){ this.dispatcher.subscribe(type,this); } doUpdate(type,arg){ console.log("接受到消息"+arg) }}//调度中心class Dispatcher{ constructor(){ this.dispatcher={}; this.id=ids++; } //订阅 subscribe(type,subscriber){ if(!this.dispatcher[type]){ this.dispatcher[type]=[]; } this.dispatcher[type].push(subscriber); } //退订 unsubscribe(type, subscriber) { let subscribers = this.dispatcher[type]; if (!subscribers || !subscribers.length) return; this.dispatcher[type] = subscribers.filter(item =>{ return item.id !== subscriber.id }); } //发布 publish(type, args) { let subscribers = this.dispatcher[type]; if (!subscribers || !subscribers.length) return; subscribers.forEach(subscriber=>{ subscriber.doUpdate(type,args); }); }}class Reader extends Subscriber{ constructor(name,dispatcher){ super(dispatcher); this.name=name; } doUpdate(type,st){ // super.update(st); console.log(this.name+`阅读了--${type}--公众号的文章`); }}class WeiX extends Dispatcher{ constructor(name){ super(); this.name=name; } publishArticle(type){ this.publish(type) }}//微信公众号平台let wx1=new WeiX();//读者们let reader1=new Reader("小玲",wx1);let reader2=new Reader("小明",wx1);let reader3=new Reader("小李",wx1);//读者订阅公众号reader1.subscribe("前端");reader2.subscribe("数据库");reader3.subscribe("数据库");//公众号发布文章wx1.publishArticle("前端");wx1.publishArticle("数据库");最后
以上是自己在阅读了《设计模式之禅》相关章节后自己对观察者模式的理解,如有不当之处还望指正!