摘要:發(fā)布者注冊(cè)發(fā)布訂閱者自動(dòng)打印消息消息觀察者模式與發(fā)布訂閱模式類(lèi)似。在此種模式中,一個(gè)目標(biāo)物件在它本身的狀態(tài)改變時(shí)主動(dòng)發(fā)出通知,觀察者收到通知從而使他們的狀態(tài)自動(dòng)發(fā)生變化。
做為非科班出身的前端er,每次聽(tīng)到設(shè)計(jì)模式都感覺(jué)很高大上,總感覺(jué)這些東西是造火箭原子彈用的,距離我們這些造螺絲釘很遙遠(yuǎn)。但是最近在做一個(gè)聊天消息的業(yè)務(wù)時(shí),發(fā)現(xiàn)貌似用上發(fā)布訂閱模式業(yè)務(wù)就很清晰了。創(chuàng)建一個(gè)消息類(lèi)當(dāng)作發(fā)布者,展示消息的函數(shù)是訂閱者,發(fā)布者提供了注冊(cè)、發(fā)布方法,訂閱者注冊(cè)后,每次調(diào)用發(fā)布方法修改數(shù)據(jù)時(shí),訂閱者函數(shù)自動(dòng)更新數(shù)據(jù)。
class MsgList{//發(fā)布者 constructor (){ this.list = []; this.fn = [] } listen(fn){//注冊(cè) this.fn.push(fn) } add(text){//發(fā)布 this.list.push(text) this.fn.map((item)=>{ item(this.list) }) } } function show(msg){//訂閱者 console.log(msg) //自動(dòng)打印 } var msg1 = new MsgList(); msg1.listen(show) msg1.add("消息1") msg1.add("消息2")
觀察者模式與發(fā)布訂閱模式類(lèi)似。在此種模式中,一個(gè)目標(biāo)物件在它本身的狀態(tài)改變時(shí)主動(dòng)發(fā)出通知,觀察者收到通知從而使他們的狀態(tài)自動(dòng)發(fā)生變化。核心就是我(觀察者)正在看著你(被觀察者),看著你目不轉(zhuǎn)睛...你只要改變我就自動(dòng)改變。概念是不是很清晰了。但是觀察者模式又跟發(fā)布訂閱有些許不太一樣的地方。
一、觀察者模式目標(biāo)和觀察者是基類(lèi),目標(biāo)提供維護(hù)觀察者的一系列方法,觀察者提供更新接口。具體觀察者和具體目標(biāo)繼承各自的基類(lèi),然后具體觀察者把自己注冊(cè)到具體目標(biāo)里,在具體目標(biāo)發(fā)生變化時(shí)候,調(diào)度觀察者的更新方法。
下面通過(guò)js來(lái)實(shí)現(xiàn)下觀察者模式。首先是目標(biāo)的構(gòu)造函數(shù),他有個(gè)數(shù)組,用于添加觀察者。還有個(gè)廣播方法,遍歷觀察者數(shù)組后調(diào)用他們的update方法:
class Subject{//目標(biāo)類(lèi)===被觀察者 constructor(){ this.subjectList = [];//目標(biāo)列表 } add(fn){//注冊(cè) this.subjectList.push(fn) } notify(context){//發(fā)通知 var subjectCount = this.subjectList.length for(var i=0; i < subjectCount; i++){ this.subjectList[i].update(context) } } //取消注冊(cè) remove(fn){ this.subjectList.splice(this.subjectList.indexOf(fn),1) } } class Observer{//觀察者類(lèi)==觀察者 update(data){ console.log("updata +" + data) } } var Subject1 = new Subject()//具體目標(biāo)1 var Subject2 = new Subject()//具體目標(biāo)2 var Observer1 = new Observer()//具體觀察者1 var Observer2 = new Observer()//具體觀察者2 Subject1.add(Observer1);//注冊(cè) //updata +test1 Subject1.add(Observer2);//注冊(cè) //updata +test1 Subject2.add(Observer1);//注冊(cè) //updata +test2 Subject1.notify("test1")//發(fā)布事件 Subject2.notify("test2")//發(fā)布事件
從上面代碼可以看出來(lái),先創(chuàng)建具體目標(biāo)和具體觀察者,然后通過(guò)add方法把具體觀察者 Observer1、Observer2注冊(cè)到具體目標(biāo)中,目標(biāo)和觀察者是直接聯(lián)系起來(lái)的,所以具體觀察者需要提供update方法。在Subject1中發(fā)通知時(shí),Observer1、Observer2都會(huì)接收通知從而更改狀態(tài)。
二、 發(fā)布/訂閱模式觀察者模式存在一個(gè)問(wèn)題,目標(biāo)無(wú)法選擇自己想要的消息發(fā)布,觀察者會(huì)接收所有消息。在此基礎(chǔ)上,出現(xiàn)了
發(fā)布/訂閱模式,在目標(biāo)和觀察者之間增加一個(gè)調(diào)度中心。訂閱者(觀察者)把自己想訂閱的事件注冊(cè)到調(diào)度中心,當(dāng)該事件觸發(fā)時(shí)候,發(fā)布者(目標(biāo))發(fā)布該事件到調(diào)度中心,由調(diào)度中心統(tǒng)一調(diào)度訂閱者注冊(cè)到調(diào)度中心的處理代碼。
class Public{//事件通道 constructor(){ this.handlers = {}; } on(eventType, handler) { // 訂閱事件 var self = this; if (!(eventType in self.handlers)) { self.handlers[eventType] = []; } self.handlers[eventType].push(handler); return self ; } emit(eventType) { // 發(fā)布事件 var self = this; var handlerArgs = Array.prototype.slice.call(arguments, 1); var length = self.handlers[eventType].length for (var i = 0; i < length; i++) { self.handlers[eventType][i].apply(self, handlerArgs); } return self; } off(eventType, handler) { // 刪除訂閱事件 var currentEvent = this.handlers[eventType]; var len = 0; if (currentEvent) { len = currentEvent.length; for (var i = len - 1; i >= 0; i--) { if (currentEvent[i] === handler) { currentEvent.splice(i, 1); } } } return self ; } } //訂閱者 function Observer1(data) { console.log("訂閱者1訂閱了:" + data) } function Observer2(data) { console.log("訂閱者2訂閱了:" + data) } var publisher = new Public(); //訂閱事件 publisher.on("a", Observer1); publisher.on("b", Observer1); publisher.on("a", Observer2); //發(fā)布事件 publisher.emit("a", "第一次發(fā)布的a事件"); publisher.emit("b", "第一次發(fā)布的b事件"); publisher.emit("a", "第二次發(fā)布的a事件"); //訂閱者1訂閱了:第一次發(fā)布a事件 //訂閱者2訂閱了:第一次發(fā)布a事件 //訂閱者1訂閱了:第一次發(fā)布b事件 //訂閱者1訂閱了:第二次發(fā)布a事件 //訂閱者2訂閱了:第二次發(fā)布a事件
可以看出來(lái),訂閱/發(fā)布模式下:訂閱和發(fā)布是不直接調(diào)度的,而是通過(guò)調(diào)度中心來(lái)完成的,訂閱者和發(fā)布者是互相不知道對(duì)方的,完全不存在耦合。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105790.html
摘要:姓名小強(qiáng)正式上班時(shí)間前端大大強(qiáng)訂閱了這個(gè)消息姓名大大強(qiáng)正式上班時(shí)間發(fā)布者發(fā)布消息前端小強(qiáng)姓名小強(qiáng)正式上班時(shí)間大大強(qiáng)姓名大大強(qiáng)正式上班時(shí)間通過(guò)添加了一個(gè),我們實(shí)現(xiàn)了對(duì)職位的判斷。 觀察者模式,定義對(duì)象間的一種一對(duì)多的依賴(lài)關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴(lài)于它的對(duì)象都將得到通知。 事實(shí)上,只要你曾經(jīng)在DOM節(jié)點(diǎn)上綁定過(guò)事件函數(shù),那么你就曾經(jīng)使用過(guò)觀察者模式了! document.b...
摘要:列舉一個(gè)生活中的例子來(lái)幫助大家理解這一種模式。例子中的小明就是訂閱者訂閱的是飯涼了,而媽媽則是發(fā)布者將信號(hào)飯涼了發(fā)布出去。這樣就不用把小明和媽媽強(qiáng)耦合在一起,當(dāng)小明的弟弟妹妹都想在飯涼了在吃飯,只需告訴媽媽一聲。 關(guān)于事件 在我們使用javascript開(kāi)發(fā)時(shí),我們會(huì)經(jīng)常用到很多事件,如點(diǎn)擊、鍵盤(pán)、鼠標(biāo)等等,這些物理性的事件。而我們今天所說(shuō)的我稱(chēng)之為事件的,是另一種形式的事件,訂閱--...
摘要:的異步完成整個(gè)異步環(huán)節(jié)的有事件循環(huán)觀察者請(qǐng)求對(duì)象以及線(xiàn)程池。執(zhí)行回調(diào)組裝好請(qǐng)求對(duì)象送入線(xiàn)程池等待執(zhí)行,實(shí)際上是完成了異步的第一部分,回調(diào)通知是第二部分。異步編程是首個(gè)將異步大規(guī)模帶到應(yīng)用層面的平臺(tái)。 showImg(https://segmentfault.com/img/remote/1460000011303472); 本文首發(fā)在個(gè)人博客:http://muyunyun.cn/po...
摘要:盡管特定環(huán)境下有各種各樣的設(shè)計(jì)模式,開(kāi)發(fā)者還是傾向于使用一些習(xí)慣性的模式。原型設(shè)計(jì)模式依賴(lài)于原型繼承原型模式主要用于為高性能環(huán)境創(chuàng)建對(duì)象。對(duì)于一個(gè)新創(chuàng)建的對(duì)象,它將保持構(gòu)造器初始化的狀態(tài)。這樣做主要是為了避免訂閱者和發(fā)布者之間的依賴(lài)。 2016-10-07 每個(gè)JS開(kāi)發(fā)者都力求寫(xiě)出可維護(hù)、復(fù)用性和可讀性高的代碼。隨著應(yīng)用不斷擴(kuò)大,代碼組織的合理性也越來(lái)越重要。設(shè)計(jì)模式為特定環(huán)境下的常見(jiàn)...
摘要:觀察者模式機(jī)動(dòng)建立一種對(duì)象與對(duì)象之間的依賴(lài)關(guān)系,一個(gè)對(duì)象發(fā)生改變時(shí)將自動(dòng)通知其他對(duì)象,其他對(duì)象將相應(yīng)做出反應(yīng)。 觀察者模式模式簡(jiǎn)介 觀察者模式(又被稱(chēng)為發(fā)布-訂閱(Publish/Subscribe)模式,屬于行為型模式的一種,它定義了一種一對(duì)多的依賴(lài)關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象。這個(gè)主題對(duì)象在狀態(tài)變化時(shí),會(huì)通知所有的觀察者對(duì)象,使他們能夠自動(dòng)更新自己。 觀察者模式機(jī)動(dòng)...
閱讀 2671·2021-10-14 09:47
閱讀 4975·2021-09-22 15:52
閱讀 3380·2019-08-30 15:53
閱讀 1477·2019-08-30 15:44
閱讀 712·2019-08-29 16:41
閱讀 1683·2019-08-29 16:28
閱讀 467·2019-08-29 15:23
閱讀 1650·2019-08-26 12:20