日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

进击的观察者模式

發布時間:2025/5/22 编程问答 60 豆豆
生活随笔 收集整理的這篇文章主要介紹了 进击的观察者模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文鏈接: 進擊的觀察者模式

商品信息改變帶來的煩惱

Talk is cheap. Show me the code. (譯: 屁話少說, 放碼過來)

以下所有代碼參見Design pattern transformation.

// 商品的信息: 價格 & 折扣 const data = {price: 100,discount: 0.8 }// 顧客信息: 是否為會員 & 購買數量 & 總消費 & 購買時間戳 const customer = {"VIP": true,"quantity": 10,"total": 0, }// 總消費計算方式 total = (info) => {if(!info.VIP) {info.total = data.price * info.quantity;} else {info.total = data.price * data.discount * info.quantity;} }total(customer); console.log('customer', customer); // customer { VIP: true, quantity: 10, total: 800 } 復制代碼

從代碼中很容易看得出來, 我們就是想實現一個簡單的計費功能. 可現實中, 商品的價格可能并不是一成不變的.

data.price = 200

價格變動后, 我們需要及時地獲取總消費, 那么就必須重新調用下 total 計費.

total(customer); console.log('customer', customer); // customer { VIP: true, quantity: 10, total: 1600 } 復制代碼

這是一個大數據時代, 任何數據都有價值. 現在, 我們還想要每次購買時的時間點.

const customer = {"VIP": true,"quantity": 10,"total": 0, + "timeStamp": 0 } // 獲取購買時間 purchaseTime = (info) => {info.timeStamp = Date.now(); } 復制代碼

于是, 我們需要執行的函數就多了一個.

total(customer) purchaseTime(customer) console.log('customer', customer) // { VIP: true, quantity: 10, total: 1600, timeStamp: 1542293676297 } 復制代碼

如果我們的需求還有很多, 而且不知一個 customer 呢. 那么, 每次價格變化我們需要執行很多步驟, 每次啊, 麻煩得很.

+ const customer1 = { + "VIP": false, + "quantity": 8, + "total": 0, + "timeStamp": 0 + }total(customer)purchaseTime(customer)func(customer)...funcN(customer1)total(customer1)purchaseTime(customer1)func(customer1)...funcN(customer)...funcN(customerN)復制代碼

現在我們就對上面的代碼進行觀察者模式改造.

用觀察者模式改造

從上面的例子中???不難看出, 每次價格變化時, 我們都需要重復調用滿足需求的方法. 不妨想想, 如果我們把這些方法存儲起來, 等到價格變化時再去統一調用, 豈不是很方便. 那么問題來了, 這和之前所說的觀察者模式(從觀察者模式說起)有什么區別呢? 在此, 我們試著用觀察者模式改造下. 首先觀察者模式都是一個套路. 先一個類維護一個列表, 對列表有增刪和通知更新功能. 另一個類則是提供了更新接口.

// 觀察目標類 class Subject {constructor() {this.observerList = []}addObserver(observer) {this.observerList.push(observer)}notify(params) {this.observerList.forEach(observer => {observer.update(params)})} }// 觀察者類 class Observer {constructor(fn) {this.update = fn} } 復制代碼

接著, 把我們想要調用的方法包裝一下, 存儲起來.

// 將要重復使用的包裝一下 observer1 = new Observer(total) observer2 = new Observer(purchaseTime)// 存起來 let subject = new Subject() subject.addObserver(observer1) subject.addObserver(observer2) 復制代碼

每次價格改變時, 只需要通知一下即可.

// 調整商品價格 data.price = 100 subject.notify(customer) subject.notify(customer1) 復制代碼

改造結束. 初看起來, 可能變得繁瑣了. 但是, 遇到復雜的情況, 這不失是一個好辦法. 接下來, 我們看看結合 Objec.defineProperty 會有什么驚喜.

與Objec.defineProperty結合

支付寶的花唄都可以自己還錢了?, 我們為什么還要別人管著?. 大家都知道經過 Objec.defineProperty 處理的對象, 在設置和獲取對象屬性的時候, 會自動觸發響應 set 和 get 方法. 利用這一點, 我們就可以做到生活自理了. 熟悉的配方, 熟悉的味道. 熟悉的套路我們不妨再走一遍.

// 觀察目標類 class Dependency {constructor() {this.watcherList = []}addObserver(observer) {this.watcherList.push(observer)}notify(params) {this.watcherList.forEach(watcher => {watcher.update(params)})} }// 觀察類 class Watcher {constructor(fn) {this.update = fn} } 復制代碼

我們此行的目的, 是要在 data.price 或 data.discount 改變時, 程序能夠自動觸發, 得到我們想要的結果. 換句話說, 通知更新的時機是在設置 data.price 或 data.discount 的時候.

Object.keys(data).forEach(key => {let value = data[key]const dep = new Dependency()Object.defineProperty(data, key, {set(newVal) {value = newValdep.notify()},get() {return value}}) }) 復制代碼

對象的每個屬性都給了一個依賴實例, 管理自己的依賴. 考慮到 customer 有很多個, 需要通知到位. 另外, 添加依賴和管理依賴, 前者是因, 后者是果. 在管理之前我們需要想好怎么添加依賴. 回頭看一看.

// 總消費計算方式 total = (info) => {if(!info.VIP) {info.total = data.price * info.quantity;} else {info.total = data.price * data.discount * info.quantity;} } // 獲取購買時間 purchaseTime = (info) => {info.timeStamp = Date.now(); } 復制代碼

我們發現, total 函數依賴于 data.price 或 data.discount 的. 如果我們在獲取屬性時去添加依賴倒是一個好時機.

class Dependency {// 省略 } + Dependency.targey = null;class Watcher {constructor(fn, key) {this.update = fn + this.key = key + this.value = this.getter()} + getter() { + Dependency.targey = this; + // 觸發下面的get() + this.value = data[this.key]; + Dependency.targey = null; + } }Object.keys(data).forEach(key => {let value = data[key]const dep = new Dependency()Object.defineProperty(data, key, {set(newVal) {value = newValdep.notify()},get() { + if (Dependency.targey) { + dep.addObserver(Dependency.targey) + }return value}}) }) 復制代碼

然而 purchaseTime 方法里并沒有 data.price 或 data.discount 可以設置. 所以這個方法行不通. 那么, 干脆緊接著依賴實例去添加依賴吧. 同時考慮到多個 customer, 我們封裝下.

// 與defineProperty結合 function defineReactive(data, watcherList, funcList) {Object.keys(data).forEach(key => {let value = data[key]const dep = new Dependency()funcList.forEach(func => {dep.addObserver(new Watcher(func))})Object.defineProperty(data, key, {set(newVal) {value = newValwatcherList.forEach(watcher => {dep.notify(watcher)})},get() {return value}})}) }defineReactive(data, [customer, customer1], [total, purchaseTime]) 復制代碼

大功告成, 價格變動時, 我們就會自動獲取到想要的結果了. 我都能自理了, 你花唄為嘛還不能自己還錢呢?

觀察者模式系列:

  • 從觀察者模式說起
  • 進擊的觀察者模式
  • 觀察者模式再次進階-發布/訂閱

總結

以上是生活随笔為你收集整理的进击的观察者模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。