国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

JavaScript 簡(jiǎn)單實(shí)現(xiàn)觀察者模式和發(fā)布-訂閱模式

這篇具有很好參考價(jià)值的文章主要介紹了JavaScript 簡(jiǎn)單實(shí)現(xiàn)觀察者模式和發(fā)布-訂閱模式。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

前言

大家好,我是南木元元,熱衷分享有趣實(shí)用的文章。今天來(lái)聊聊設(shè)計(jì)模式中常用的觀察者模式和發(fā)布-訂閱模式。

觀察者模式

概念

觀察者模式定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都將得到通知。

如何理解這句話呢?來(lái)舉個(gè)生活中的例子

學(xué)生小明情緒比較容易波動(dòng),所以當(dāng)小明的情緒發(fā)生變化時(shí),父母和老師希望及時(shí)獲得通知,以便可以采取適當(dāng)?shù)拇胧﹣?lái)幫助他。

  • 首先家長(zhǎng)和老師(觀察者)都會(huì)告訴小明他們對(duì)他的情緒狀態(tài)很關(guān)注。(訂閱事件)
  • 當(dāng)小明(被觀察者)的情緒發(fā)生變化時(shí),他會(huì)通知所有注冊(cè)過(guò)的觀察者。例如,如果小明感到很開(kāi)心,他會(huì)告訴父母和老師:“我今天心情很好!”;如果他感到沮喪,他也會(huì)告訴父母和老師:“我今天感覺(jué)不太好?!保ㄍㄖ兓?/li>

這樣父母和老師就能及時(shí)了解小明的情緒狀態(tài),當(dāng)小明情緒低落時(shí),他們可以給予他關(guān)心、安慰和支持。
在這個(gè)例子中,小明就是被觀察者,而父母和老師都是觀察者。

代碼實(shí)現(xiàn)

觀察者模式有何應(yīng)用呢?

Vue的響應(yīng)式就是基于觀察者模式的,下面就來(lái)簡(jiǎn)單實(shí)現(xiàn)一下它的代碼。

// 被觀察者 學(xué)生
class Subject {
  constructor() {
    this.state = "happy";
    this.observers = []; // 存儲(chǔ)所有的觀察者
  }
  //新增觀察者
  add(o) {
    this.observers.push(o);
  }
  //獲取狀態(tài)
  getState() {
    return this.state;
  }
  // 更新?tīng)顟B(tài)并通知
  setState(newState) {
    this.state = newState;
    this.notify();
  }
  //通知所有的觀察者
  notify() {
    this.observers.forEach((o) => o.update(this));
  }
}

// 觀察者 父母和老師
class Observer {
  constructor(name) {
    this.name = name;
  }
  //更新
  update(student) {
    console.log(`親愛(ài)的${this.name} 通知您當(dāng)前學(xué)生的狀態(tài)是${student.getState()}`);
  }
}

let student = new Subject();
let parent = new Observer("父母");
let teacher = new Observer("老師");
//添加觀察者
student.add(parent);
student.add(teacher);
//設(shè)置被觀察者的狀態(tài)
student.setState("sad");

輸出結(jié)果:
JavaScript 簡(jiǎn)單實(shí)現(xiàn)觀察者模式和發(fā)布-訂閱模式,設(shè)計(jì)模式,javascript,設(shè)計(jì)模式

發(fā)布-訂閱模式

概念

發(fā)布訂閱模式跟觀察者模式很像,它們其實(shí)都有發(fā)布者訂閱者,但是他們是有區(qū)別的:

  • 觀察者模式的發(fā)布和訂閱是互相依賴的
  • 發(fā)布訂閱模式的發(fā)布和訂閱是不互相依賴的,因?yàn)橛幸粋€(gè)統(tǒng)一調(diào)度中心

為了更好區(qū)分這兩種設(shè)計(jì)模式,接著上述例子。

  • 所有老師都希望訂閱小明的情緒狀態(tài),他們向情緒監(jiān)測(cè)系統(tǒng)注冊(cè)自己,來(lái)時(shí)刻關(guān)注小明的情緒。(向調(diào)度中心訂閱事件)
  • 當(dāng)小明的情緒發(fā)生變化時(shí),情緒監(jiān)測(cè)系統(tǒng)會(huì)將消息發(fā)布給所有訂閱了小明情緒狀態(tài)的老師。例如,如果小明在上課時(shí)感到煩躁,情緒監(jiān)測(cè)系統(tǒng)會(huì)發(fā)布消息給老師:“小明情緒不穩(wěn)定,請(qǐng)關(guān)注他的情緒變化。”(調(diào)度中心通知變化)

通過(guò)發(fā)布訂閱模式,小明不需要直接告訴每位老師他的情緒狀態(tài),而是通過(guò)情緒監(jiān)測(cè)系統(tǒng)自動(dòng)發(fā)布消息給所有訂閱了他情緒狀態(tài)的老師。這種發(fā)布者不直接接觸到訂閱者的模式,就是發(fā)布訂閱模式。
JavaScript 簡(jiǎn)單實(shí)現(xiàn)觀察者模式和發(fā)布-訂閱模式,設(shè)計(jì)模式,javascript,設(shè)計(jì)模式
那么發(fā)布訂閱模式有何應(yīng)用呢?
Vue的EventBus事件總線其實(shí)就是用了發(fā)布訂閱模式。用法如下:
1.創(chuàng)建全局事件總線

// main.js
import Vue from "vue"
Vue.prototype.$bus = new Vue()

2.通過(guò)on訂閱事件

//組件A
export default{
    mounted(){
        // 監(jiān)聽(tīng)事件的觸發(fā)
        this.$bus.$on("sendMsg", data => {
            console.log(data)//身體健康
        })
    },
    beforeDestroy(){
        // 取消監(jiān)聽(tīng)
        this.$bus.$off("sendMsg")
    }
}

3.通過(guò)emit發(fā)布事件

//組件B
<template>
    <button @click="handlerClick">點(diǎn)擊發(fā)送數(shù)據(jù)</button>
</template>
export default{
    methods:{
        handlerClick(){
            this.$bus.$emit("sendMsg", "身體健康")
        }
    }
}

了解了EventBus的使用后,那么接下來(lái)就來(lái)手動(dòng)實(shí)現(xiàn)一個(gè)EventBus。

代碼實(shí)現(xiàn)

基礎(chǔ)版

實(shí)現(xiàn)目標(biāo):使用 $on 訂閱事件,使用 $emit 發(fā)布事件。
主要思路:

  • 創(chuàng)建一個(gè)緩存列表對(duì)象,存放訂閱的事件名和回調(diào)
  • on 方法用來(lái)把回調(diào)函數(shù)都加到緩存列表中(訂閱者注冊(cè)事件到調(diào)度中心)
  • emit方法根據(jù)事件名去逐個(gè)執(zhí)行對(duì)應(yīng)緩存列表中的函數(shù)(發(fā)布者發(fā)布事件到調(diào)度中心)
class EventBus {
  constructor() {
    // 緩存列表,用來(lái)存放注冊(cè)的事件與回調(diào)
    this.cache = {};
  }

  // 訂閱事件
  on(name, cb) {
    // 如果當(dāng)前事件沒(méi)有訂閱過(guò),就給事件創(chuàng)建一個(gè)隊(duì)列
    if (!this.cache[name]) {
      this.cache[name] = []; //由于一個(gè)事件可能注冊(cè)多個(gè)回調(diào)函數(shù),所以使用數(shù)組來(lái)存儲(chǔ)事件隊(duì)列
    }
    this.cache[name].push(cb); 
  }

  // 觸發(fā)事件
  emit(name, ...args) {
    // 檢查目標(biāo)事件是否有監(jiān)聽(tīng)函數(shù)隊(duì)列
    if (this.cache[name]) {
      // 逐個(gè)調(diào)用隊(duì)列里的回調(diào)函數(shù)
      this.cache[name].forEach((callback) => {
        callback(...args);
      });
    }
  }
}

// 測(cè)試
let eventBus = new EventBus();
// 訂閱事件
eventBus.on("teacherName1", (pos, state) => {
  console.log(`訂閱者小陳老師,小明同學(xué)當(dāng)前在${pos},心情狀態(tài)是${state}`);
});
eventBus.on("teacherName1", (pos, state) => {
  console.log(`訂閱者小陳老師,小明同學(xué)當(dāng)前在${pos},心情狀態(tài)是${state}`);
});
eventBus.on("teacherName2", (pos, state) => {
  console.log(`訂閱者小李老師,小明同學(xué)當(dāng)前在${pos},心情狀態(tài)是${state}`);
});
// 發(fā)布事件
eventBus.emit("teacherName1", "教室", "傷心");
eventBus.emit("teacherName2", "操場(chǎng)", "開(kāi)心");

輸出結(jié)果:

JavaScript 簡(jiǎn)單實(shí)現(xiàn)觀察者模式和發(fā)布-訂閱模式,設(shè)計(jì)模式,javascript,設(shè)計(jì)模式

取消訂閱

實(shí)現(xiàn)目標(biāo):增加 off 方法取消訂閱。

  • off 方法:找到當(dāng)前取消事件名對(duì)應(yīng)的函數(shù)隊(duì)列中相應(yīng)回調(diào),進(jìn)行刪除
class EventBus {
  constructor() {
    // 緩存列表,用來(lái)存放注冊(cè)的事件與回調(diào)
    this.cache = {};
  }

  // 訂閱事件
  on(name, cb) {
    // 如果當(dāng)前事件沒(méi)有訂閱過(guò),就給事件創(chuàng)建一個(gè)隊(duì)列
    if (!this.cache[name]) {
      this.cache[name] = []; //由于一個(gè)事件可能注冊(cè)多個(gè)回調(diào)函數(shù),所以使用數(shù)組來(lái)存儲(chǔ)事件隊(duì)列
    }
    this.cache[name].push(cb); 
  }

  // 觸發(fā)事件
  emit(name, ...args) {
    // 檢查目標(biāo)事件是否有監(jiān)聽(tīng)函數(shù)隊(duì)列
    if (this.cache[name]) {
      // 逐個(gè)調(diào)用隊(duì)列里的回調(diào)函數(shù)
      this.cache[name].forEach((callback) => {
        callback(...args);
      });
    }
  }

  // 取消訂閱
  off(name, cb) {
    const callbacks = this.cache[name]; 
    const index = callbacks.indexOf(cb); 
    if (index !== -1) {
      callbacks.splice(index, 1); 
    }
  }
}

// 測(cè)試
let eventBus = new EventBus();
let event1 = function (...args) {
  console.log(`通知1-訂閱者小陳老師,小明同學(xué)當(dāng)前心情狀態(tài):${args}`)
};
let event2 = function (...args) {
  console.log(`通知2-訂閱者小陳老師,小明同學(xué)當(dāng)前心情狀態(tài):${args}`)
};
// 訂閱事件
eventBus.on("teacherName1", event1);
eventBus.on("teacherName1", event2);
// 取消訂閱事件1
eventBus.off('teacherName1', event1);
// 發(fā)布事件
eventBus.emit("teacherName1", "教室", "上課", "打架", "憤怒");
eventBus.emit("teacherName2", "教室", "上課", "打架", "憤怒");

輸出結(jié)果:

JavaScript 簡(jiǎn)單實(shí)現(xiàn)觀察者模式和發(fā)布-訂閱模式,設(shè)計(jì)模式,javascript,設(shè)計(jì)模式

訂閱一次

實(shí)現(xiàn)目標(biāo):增加 once 方法只訂閱一次。

  • once 方法只監(jiān)聽(tīng)一次,執(zhí)行完第一次回調(diào)函數(shù)后,自動(dòng)刪除當(dāng)前訂閱事件
class EventBus {
  constructor() {
    // 緩存列表,用來(lái)存放注冊(cè)的事件與回調(diào)
    this.cache = {};
  }

  // 訂閱事件
  on(name, cb) {
    // 如果當(dāng)前事件沒(méi)有訂閱過(guò),就給事件創(chuàng)建一個(gè)隊(duì)列
    if (!this.cache[name]) {
      this.cache[name] = []; //由于一個(gè)事件可能注冊(cè)多個(gè)回調(diào)函數(shù),所以使用數(shù)組來(lái)存儲(chǔ)事件隊(duì)列
    }
    this.cache[name].push(cb); 
  }

  // 觸發(fā)事件
  emit(name, ...args) {
    // 檢查目標(biāo)事件是否有監(jiān)聽(tīng)函數(shù)隊(duì)列
    if (this.cache[name]) {
      // 逐個(gè)調(diào)用隊(duì)列里的回調(diào)函數(shù)
      this.cache[name].forEach((callback) => {
        callback(...args);
      });
    }
  }

  // 取消訂閱
  off(name, cb) {
    const callbacks = this.cache[name]; 
    const index = callbacks.indexOf(cb); 
    if (index !== -1) {
      callbacks.splice(index, 1); 
    }
  }

  // 只訂閱一次
  once(name, cb) {
    // 執(zhí)行完第一次回調(diào)函數(shù)后,自動(dòng)刪除當(dāng)前訂閱事件
    const fn = (...args) => {
      cb(...args); 
      this.off(name, fn); 
    };
    this.on(name, fn);
  }
}

// 測(cè)試
let eventBus = new EventBus();
let event1 = function (...args) {
  console.log(`通知1-訂閱者小陳老師,小明同學(xué)當(dāng)前心情狀態(tài):${args}`)
};
// 訂閱事件,只訂閱一次
eventBus.once("teacherName1", event1);
// 發(fā)布事件
eventBus.emit("teacherName1", "教室", "上課", "打架", "憤怒");
eventBus.emit("teacherName1", "教室", "上課", "打架", "憤怒");
eventBus.emit("teacherName1", "教室", "上課", "打架", "憤怒");

輸出結(jié)果:

JavaScript 簡(jiǎn)單實(shí)現(xiàn)觀察者模式和發(fā)布-訂閱模式,設(shè)計(jì)模式,javascript,設(shè)計(jì)模式

結(jié)語(yǔ)

??如果此文對(duì)你有幫助的話,歡迎??關(guān)注、??點(diǎn)贊、?收藏、??評(píng)論,支持一下博主~文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-661793.html

到了這里,關(guān)于JavaScript 簡(jiǎn)單實(shí)現(xiàn)觀察者模式和發(fā)布-訂閱模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 設(shè)計(jì)模式之觀察者(發(fā)布訂閱)模式

    設(shè)計(jì)模式之觀察者(發(fā)布訂閱)模式

    觀察者模式定義了一種一對(duì)多的依賴關(guān)系,讓多個(gè)觀察者對(duì)象同事監(jiān)聽(tīng)某一個(gè)主題對(duì)象。這個(gè)主題對(duì)象在狀態(tài)發(fā)生變化時(shí),會(huì)通知所有觀察者對(duì)象,使它們能夠自動(dòng)更新自己 觀察者模式主要解決的問(wèn)題: 當(dāng)一個(gè)對(duì)象狀態(tài)發(fā)生改變后給其他的對(duì)象通知 觀察者的優(yōu)點(diǎn): 觀察者和

    2024年02月07日
    瀏覽(87)
  • 觀察者模式, 發(fā)布-訂閱模式, 監(jiān)聽(tīng)器模式

    觀察者模式, 發(fā)布-訂閱模式, 監(jiān)聽(tīng)器模式

    觀察者模式是一種 行為型 設(shè)計(jì)模式, 定義對(duì)象間的一種 一對(duì)多 的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新 角色模型和結(jié)構(gòu)圖 在觀察者模式中,只有兩種主體:目標(biāo)對(duì)象 ( Object ) 和 觀察者 ( Observer )。宗門(mén)任務(wù)大殿就是目標(biāo)對(duì)象

    2024年02月22日
    瀏覽(89)
  • C++之觀察者模式(發(fā)布-訂閱)

    C++之觀察者模式(發(fā)布-訂閱)

    目錄 模式簡(jiǎn)介 介紹 優(yōu)點(diǎn) 缺點(diǎn) 代碼實(shí)現(xiàn) 場(chǎng)景說(shuō)明 實(shí)現(xiàn)代碼 運(yùn)行結(jié)果 觀察者模式( Observer Pattern ) ,也叫我們熟知的 發(fā)布-訂閱模式。 它是一種 行為型模式。 介紹 觀察者模式主要關(guān)注的是對(duì)象的一對(duì)多的關(guān)系, 也就是多個(gè)對(duì)象依賴于一個(gè)對(duì)象,當(dāng)該對(duì)象的 狀態(tài)發(fā)生改變

    2024年02月15日
    瀏覽(93)
  • 觀察者模式、中介者模式和發(fā)布訂閱模式

    觀察者模式、中介者模式和發(fā)布訂閱模式

    觀察者模式定義了對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都將得到通知,并自動(dòng)更新 觀察者模式屬于行為型模式,行為型模式關(guān)注的是對(duì)象之間的通訊,觀察者模式就是觀察者和被觀察者之間的通訊 例如生活中,我們可以用報(bào)

    2024年02月15日
    瀏覽(88)
  • javascript設(shè)計(jì)模式-觀察者和命令

    觀察者 是一種管理人與任務(wù)之間的關(guān)系的得力工具,實(shí)質(zhì)就是你可以對(duì)程序中某個(gè)對(duì)象的狀態(tài)進(jìn)行觀察,并且在其發(fā)生改變時(shí)能夠得到通知。一般有兩種實(shí)現(xiàn)方式推或拉,在這個(gè)過(guò)程中各方的職責(zé)如下: 訂閱者可以訂閱和退訂,他們還要接收,并且可以在由人投送和自己收

    2024年01月23日
    瀏覽(90)
  • JavaScript設(shè)計(jì)模式(四)——策略模式、代理模式、觀察者模式

    JavaScript設(shè)計(jì)模式(四)——策略模式、代理模式、觀察者模式

    個(gè)人簡(jiǎn)介 ?? 個(gè)人主頁(yè): 前端雜貨鋪 ???♂? 學(xué)習(xí)方向: 主攻前端方向,正逐漸往全干發(fā)展 ?? 個(gè)人狀態(tài): 研發(fā)工程師,現(xiàn)效力于中國(guó)工業(yè)軟件事業(yè) ?? 人生格言: 積跬步至千里,積小流成江海 ?? 推薦學(xué)習(xí):??前端面試寶典 ??Vue2 ??Vue3 ??Vue2/3項(xiàng)目實(shí)戰(zhàn) ??Node.js??

    2024年02月09日
    瀏覽(92)
  • 從Vue層面 - 解析發(fā)布訂閱模式和觀察者模式區(qū)別

    從Vue層面 - 解析發(fā)布訂閱模式和觀察者模式區(qū)別

    觀察者模式和發(fā)布訂閱模式作為日常開(kāi)發(fā)中經(jīng)常使用到的模式,我一直不能做到很好的區(qū)分。最近在看Vue的源碼,里面設(shè)計(jì)到了觀察者模式,比較感興趣,就去學(xué)習(xí)了下,這里做個(gè)總結(jié)吧。 基于一個(gè) 事件中心 ,接收通知的對(duì)象是訂閱者,需要先訂閱某個(gè)事件,觸發(fā)事件的對(duì)

    2024年02月15日
    瀏覽(90)
  • 設(shè)計(jì)模式(四) —— 觀察者模式/發(fā)布訂閱模式,c和c++示例代碼

    往期地址: 設(shè)計(jì)模式(一)——簡(jiǎn)單工廠模式 設(shè)計(jì)模式(二)——策略模式 設(shè)計(jì)模式(三)——裝飾模式 本期主題: 使用c和c++代碼,講解觀察者模式、發(fā)布訂閱模式 發(fā)布-訂閱模式是一種行為設(shè)計(jì)模式,它允許多個(gè)對(duì)象通過(guò)事件的發(fā)布和訂閱來(lái)進(jìn)行通信; 在這種模式中,

    2023年04月17日
    瀏覽(93)
  • 觀察者模式(上):詳解各種應(yīng)用場(chǎng)景下觀察者模式的不同實(shí)現(xiàn)方式

    ????????從今天起,我們開(kāi)始學(xué)習(xí)行為型設(shè)計(jì)模式。我們知道,創(chuàng)建型設(shè)計(jì)模式主要解決“對(duì)象的創(chuàng)建”問(wèn)題,結(jié)構(gòu)型設(shè)計(jì)模式主要解決“類或?qū)ο蟮慕M合或組裝”問(wèn)題,那行為型設(shè)計(jì)模式主要解決的就是“ 類或?qū)ο笾g的交互 ”問(wèn)題。 原理及應(yīng)用場(chǎng)景剖析 在對(duì)象之間

    2024年02月16日
    瀏覽(85)
  • Java設(shè)計(jì)模式-觀察者模式-SpringBoot實(shí)現(xiàn)

    Java設(shè)計(jì)模式-觀察者模式-SpringBoot實(shí)現(xiàn)

    項(xiàng)目:https://gitee.com/KakarottoChen/blog-code.git 的:JavaSpringListener Java觀察者模式是一種設(shè)計(jì)模式,用于實(shí)現(xiàn)對(duì)象之間的一對(duì)多依賴關(guān)系。在觀察者模式中,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生變化時(shí),它的所有依賴對(duì)象(觀察者)都會(huì)自動(dòng)收到通知并進(jìn)行相應(yīng)的更新。 觀察者模式由以下幾個(gè)核

    2024年02月08日
    瀏覽(89)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包