JS設(shè)計(jì)模式-觀察者模式(核心)

觀察者模式是前端設(shè)計(jì)模式的核心

介紹
  • 發(fā)布 & 訂閱
  • 一對(duì)多
    什么是發(fā)布 & 訂閱?

    我說好了一件事情,等著別人來做。 比如,我躺在家里,訂了一份外賣,然后等著,會(huì)有人來給你觸發(fā)。
    一對(duì)多就像一個(gè)拍賣品一樣,同時(shí)可以有多個(gè)人觀察它。
UML類圖
uml_observer.png

左側(cè)是Observer,就是觀察者,它有一個(gè)update方法,當(dāng)觀察者需要被觸發(fā)的時(shí)候執(zhí)行update。
右側(cè)是主題,主題可以綁定多個(gè)觀察者,放在observers里面。
主題可以獲取狀態(tài)(getState()),也可以設(shè)置狀態(tài)(setState())
當(dāng)狀態(tài)設(shè)置完成后,他會(huì)觸發(fā)所有的觀察者(notifyAllObservers()),
觸發(fā)所有觀察者里面的update方法。
觀察者定義好以后,它就等待被更新,等待被觸發(fā),當(dāng)然,前提是它已經(jīng)定義好了。
注意一對(duì)多,主題是一個(gè),但是觀察者可能是多個(gè)。
可能還不是很理解,可以看看下面代碼演示,仔細(xì)看幾遍,比較容易理解。

代碼演示
// 主題,接收狀態(tài)變化,觸發(fā)每個(gè)觀察者
class Subject {
  constructor() {
      this.state = 0
      this.observers = []
  }
  getState() {
      return this.state
  }
  setState(state) {
      this.state = state
      this.notifyAllObservers()
  }
  attach(observer) {
      this.observers.push(observer)
  }
  notifyAllObservers() {
      this.observers.forEach(observer => {
          observer.update()
      })
  }
}

// 觀察者,等待被觸發(fā)
class Observer {
  constructor(name, subject) {
      this.name = name
      this.subject = subject
      this.subject.attach(this)
  }
  update() {
      console.log(`${this.name} update, state: ${this.subject.getState()}`)
  }
}

// 測(cè)試代碼
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
let o3 = new Observer('o3', s)

s.setState(1)
s.setState(2)
s.setState(3)

運(yùn)行結(jié)果如下圖


image.png
場(chǎng)景
  • 網(wǎng)頁(yè)事件綁定
  • Promise
  • jQuery callbacks
  • nodejs 自定義事件
網(wǎng)頁(yè)事件綁定
<button id="btn1">btn</button>
<script>
   $('#app').click(function(){
    console.log(11);
   })
   $('#app').click(function(){
    console.log(22);
   })
   $('#app').click(function(){
    console.log(33);
   })
</script>
//  每次點(diǎn)擊都會(huì)打印 11 22 33
Promise
var src = 'http://www.imooc.com/static/img/index/logo_new.png'
var result = loadImg(src)
console.log(result)

result.then(function (img) {
  console.log('success 1')
}, function () {    
  console.log('failed 1')
})
// then就是一個(gè)觀察者,等待前一個(gè)處理完成
Jquery $.Callbacks()
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <p>jQuery callbacks</p>    

    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script>
        // 自定義事件,自定義回調(diào)
        var callbacks = $.Callbacks() // 注意大小寫
        callbacks.add(function (info) {
            console.log('fn1', info)
        })
        callbacks.add(function (info) {
            console.log('fn2', info)
        })
        callbacks.add(function (info) {
            console.log('fn3', info)
        })
        callbacks.fire('gogogo')
        callbacks.fire('fire')
    </script>
</body>
</html>
nodejs 自定義事件
const EventEmitter = require('events').EventEmitter

const emitter1 = new EventEmitter()
emitter1.on('some', () => {
    // 監(jiān)聽 some 事件
    console.log('some event is occured 1')
})
emitter1.on('some', () => {
    // 監(jiān)聽 some 事件
    console.log('some event is occured 2')
})
// 觸發(fā) some 事件
emitter1.emit('some')

繼承

const EventEmitter = require('events').EventEmitter

// 任何構(gòu)造函數(shù)都可以繼承 EventEmitter 的方法 on emit
class Dog extends EventEmitter {
    constructor(name) {
        super()
        this.name = name
    }
}
var simon = new Dog('simon')
simon.on('bark', function () {
    console.log(this.name, ' barked')
})
setInterval(() => {
    simon.emit('bark')
}, 500)
var fs = require('fs')
var readStream = fs.createReadStream('./data/file1.txt')  // 讀取文件的 Stream

var length = 0
readStream.on('data', function (chunk) {
    length += chunk.toString().length
})
readStream.on('end', function () {
    console.log(length)
})
const EventEmitter = require('events').EventEmitter

// 任何構(gòu)造函數(shù)都可以繼承 EventEmitter 的方法 on emit
class Dog extends EventEmitter {
    constructor(name) {
        super()
        this.name = name
    }
}
var simon = new Dog('simon')
simon.on('bark', function () {
    console.log(this.name, ' barked')
})
setInterval(() => {
    simon.emit('bark')
}, 500)
var fs = require('fs')
var readStream = fs.createReadStream('./data/file1.txt')  // 讀取文件的 Stream

var length = 0
readStream.on('data', function (chunk) {
    length += chunk.toString().length
})
readStream.on('end', function () {
    console.log(length)
})
var readline = require('readline');
var fs = require('fs')

var rl = readline.createInterface({
    input: fs.createReadStream('./data/file1.txt')
});

var lineNum = 0
rl.on('line', function(line){
    lineNum++
});
rl.on('close', function() {
    console.log('lineNum', lineNum)
});
其他場(chǎng)景
  • nodejs中:處理http請(qǐng)求,多進(jìn)程通訊
  • vue和react組件生命周期觸發(fā)
  • vue watch
nodejs 處理http請(qǐng)求
var http = require('http')

function serverCallback(req, res) {
    var method = req.method.toLowerCase() // 獲取請(qǐng)求的方法
    if (method === 'get') {
    }
    if (method === 'post') {
        // 接收 post 請(qǐng)求的內(nèi)容
        var data = ''
        req.on('data', function (chunk) {
            // “一點(diǎn)一點(diǎn)”接收內(nèi)容
            console.log('chunk', chunk.toString())
            data += chunk.toString()
        })
        req.on('end', function () {
            // 接收完畢,將內(nèi)容輸出
            console.log('end')
            res.writeHead(200, {'Content-type': 'text/html'})
            res.write(data)
            res.end()
        })
    }
    
}
http.createServer(serverCallback).listen(8081)  // 注意端口別和其他 server 的沖突
console.log('監(jiān)聽 8081 端口……')
設(shè)計(jì)原則驗(yàn)證
  • 主題和觀察者分離,不是主動(dòng)觸發(fā)而是被動(dòng)監(jiān)聽,兩者解耦
  • 符合開放封閉原則
  1. 本文資料來自慕課網(wǎng)-雙越老師-Javascript 設(shè)計(jì)模式系統(tǒng)講解與應(yīng)用視頻課程。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.幾種基本數(shù)據(jù)類型?復(fù)雜數(shù)據(jù)類型?值類型和引用數(shù)據(jù)類型?堆棧數(shù)據(jù)結(jié)構(gòu)? 基本數(shù)據(jù)類型:Undefined、Nul...
    極樂君閱讀 5,869評(píng)論 0 106
  • $HTML, HTTP,web綜合問題 1、前端需要注意哪些SEO 2、 的title和alt有什么區(qū)別 3、HT...
    Hebborn_hb閱讀 4,763評(píng)論 0 20
  • PNG 有PNG8和truecolor PNG PNG8類似GIF顏色上限為256,文件小,支持alpha透明度,...
    hudaren閱讀 1,827評(píng)論 0 0
  • 觀察者設(shè)計(jì)模式是一個(gè)好的設(shè)計(jì)模式,這個(gè)模式我們?cè)陂_發(fā)中比較常見,尤其是它的變形模式訂閱/發(fā)布者模式我們更是很熟悉,...
    緣自世界閱讀 306評(píng)論 0 3
  • 念 別離 苦斷腸 淚眼朦朧 人去樓已空 獨(dú)留御酒誰(shuí)飲 滿地錦緞何冢葬 孤桿棹影伶仃扁舟 山消水逝催白兩鬢頭 夜撫衣...
    小橋流水人家l閱讀 186評(píng)論 0 3

友情鏈接更多精彩內(nèi)容