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