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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Design Pattern: Observer Pattern

發(fā)布時(shí)間:2025/3/20 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Design Pattern: Observer Pattern 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1. Brief                            

? 一直對(duì)Observer Pattern和Pub/Sub Pattern有所混淆,下面打算通過這兩篇Blog來梳理這兩種模式。若有紕漏請(qǐng)大家指正。

?

2. Use Case                          

? 首先我們來面對(duì)一個(gè)老到跌渣的故事,并以從未聽說過Observer Pattern為前提。

? 假設(shè)要設(shè)計(jì)一個(gè)新聞?dòng)嗛喯到y(tǒng),新聞分為商業(yè)、體育和八卦3種,而查收終端有PC、移動(dòng)終端等,后續(xù)還不斷增加新聞種類和查收終端。

? 需求如上,下面我們根據(jù)OOD的方式來構(gòu)建概念模型。

? 新聞 <- 分類新聞

? 終端 <- 分類終端

? 然后構(gòu)造實(shí)體模型

// 新聞相關(guān)實(shí)體模型 class NewsType{constructor(){} } class BusinessNewsType extends NewsType{} class SportNewsType extends NewsType{} class EntertaintmentNewsType extends NewsType{}// 終端相關(guān)實(shí)體模型 class Term{getNews(news){} } class PCTerm extend Term{} class MobileTerm extend Term{}

? ?接著我們關(guān)聯(lián)已有經(jīng)驗(yàn)——現(xiàn)實(shí)生活中的送報(bào)服務(wù),發(fā)現(xiàn)用戶A、用戶B均訂閱了A報(bào)的X早報(bào),那么每天早上報(bào)紙剛印刷出來就會(huì)馬上送到用戶A和B那了。突然 多了家訂報(bào)有米送的Y早報(bào),用戶A和用戶C跑去訂閱,用戶B直接就退了X早報(bào),這時(shí)X早報(bào)為留住老用戶就推送“老客戶免費(fèi)贈(zèng)送半年X晚報(bào)”,于是用戶A取 消了退訂的想法。

? 很明顯?新聞?dòng)嗛喯到y(tǒng) 就是線下業(yè)務(wù)直挪到線上的做法,通過分析線下業(yè)務(wù)流程我們可以找到設(shè)計(jì)方案。線下業(yè)務(wù)流程如下:

? 訂閱:用戶到報(bào)社訂閱

? 退訂:用戶到報(bào)社退訂

? 分發(fā)報(bào)紙:報(bào)社向所有訂閱者分發(fā)報(bào)紙

? 按這思路構(gòu)建 新聞?dòng)嗛喯到y(tǒng) 的原型:

class NewsType{constructor(){this.subs = []}/* 訂閱* @param {Term} term - 終端* @returns {Boolean}*/sub(term){// 排除for(let _sub of this.subs) if(_sub === term) return falsereturn Boolean(this.subs.push(term))}/* 退訂* @param {Term} term - 終端* @return {Boolean}*/unsub(term){for(let i = 0, sub; sub = subs[i]; ++i)if(sub === term) return Boolean(this.subs.splice(i, 1))}/** 分發(fā)新聞*/notify(news){for(let sub of this.subs) sub.getNews(news)} } class BusinessNewsType extends NewsType{pubNews(title, content){var news = {title: title, content: content}super.notify(news)} } // definition of SportNewsType.......class PCTerm extends Term{getNews(news){alert(news.title + ';' + news.content)} } class MobileTerm extends Term{getNews(news){console.log(news.title + ';' + news.content)} }// 主程序則作為 新聞中心 與 用戶交互的場(chǎng)所 var businessNewsType = new BusinessNewsType() var sportNewsType = new SportNewsType() var pcTerm = new PCTerm() var mobileTerm = new MobileTerm() businessNewsType.sub(pcTerm) businessNewsType.sub(mobileTerm) sportNewsType.sub(mobileTerm)

上述原型基本勾勒出新聞?dòng)嗛喯到y(tǒng)中對(duì)象及其關(guān)聯(lián)的方式,我們就可以在這之上再細(xì)化和優(yōu)化了。而從上述是原型我們不難發(fā)現(xiàn) 新聞 與 終端 均可獨(dú)立開發(fā),然后在主程序中做關(guān)聯(lián)即可。新聞?lì)愋?和 終端類型的增刪并不會(huì)對(duì)其他已有的新聞?lì)愋秃徒K端類型有影響,除了在主程序中增刪關(guān)聯(lián)外。

? 現(xiàn)在我們作個(gè)簡(jiǎn)單的分析總結(jié):

? 1. 不穩(wěn)定因素(新聞?lì)愋?和 終端類型)解耦 -> 最小化不穩(wěn)定因素所影響的范圍(范圍越小,后期改動(dòng)越少);

? 2. 關(guān)聯(lián)規(guī)則接口/契約化 -> 固化關(guān)聯(lián)規(guī)則 和 關(guān)聯(lián)發(fā)生的形式 便于后期維護(hù)。

? 這些是我面對(duì)未知問題的分析、解構(gòu)方法,希望和大家一起探討更美好的方法。

?

3. What Is Observer Pattern?                

? Observer Pattern(觀察者模式),狹義上是指Observer/Subscriber關(guān)注Observable/Subject的狀態(tài),并根據(jù) Observable/Subject的狀態(tài)作出響應(yīng)。廣義上是指Observer/Subscriber關(guān)注Observable/Subject的狀 態(tài)或行為或兩者兼?zhèn)?#xff0c;并作出響應(yīng)。

? Roles

? ??Observable/Subject(被觀察者):定義被觀察者的公共狀態(tài)和行為

? ? ConcreteObservable(具體的被觀察者):定義具體的被觀察者的狀態(tài)和行為

? ? Observer(觀察者):定義觀察者的公共狀態(tài)和行為

? ? ConcreteObserver(具體的觀察者):定義具體的觀察者的狀態(tài)和行為

? Two Methods: Push & Pull

? ? 上面第2節(jié)中的實(shí)現(xiàn)是由Observable/Subject來維護(hù)Observer組,那是不是只能這樣呢?答案是否定的。它只是Push方式的實(shí)現(xiàn),我們還可以采用Pull方式呢!

? ? Push Model:推方式,也就是由Observable/Subject主動(dòng)發(fā)起與Observer/Subscriber通信,并將自身的所有信息推給Observer/Subscriber,即使大部分信息最后都沒用上。

? ?   pros:?1. 觀察者實(shí)時(shí)響應(yīng)被觀察者的狀態(tài)變化和行為狀況;

? ? ? ? ? cons: 1. 觀察者被硬塞一些被觀察者的無效信息;2. 被觀察者狀態(tài)變化頻密,導(dǎo)致觀察者忙于響應(yīng),消耗資源。

? ? Pull Model:拉方式,也就是由主動(dòng)Observer/Subscriber發(fā)起與Observable/Subject通信,并根據(jù)自身需要從Observable/Subject上拉去有效信息。一般通過定時(shí)器或特定事件觸發(fā)執(zhí)行。

? ? ? ? ?pros: 1. 觀察者可按需從被觀察者處提取有效信息;2. 自主控制通信節(jié)奏,以免被狀態(tài)頻密變化的被觀察者牽著鼻子走;

? ? ? ? ?cons: 1. 獲取被觀察者狀態(tài)變化上存在滯后甚至丟失的情況。

? ? 下面是Pull Model的實(shí)現(xiàn)方式

// Pull Model implementation class FooNewsType{constructor(){this.news = []}addNews(title, content){this.news.push({title: title, content: content, timestamp:(+new Date())})} }class PCTerm{constructor(){this.subjects = []this.newsTiles = []this.lastPullDate = 0}subTo(newsType){this.subjects.push(newType)}unsubFrom(newsType){for(let i = 0, n; n = this.subjects[i]; ++i)if(n === newsType) return this.subjects.splice(i, 1)}// 拉數(shù)據(jù)pull(){for(let sub of this.subjects)for(let news of sub.news)if(news.timestamp > this.lastPullDate)this.newsTiles .push(news.title)} }// 主程序 var businessNewsType = new BusinessNewsType() var pcTerm = new PCTerm() pcTerm.subTo(businessNewsType) businessNewsType .addNews('Say Hi', 'Hello World!') // 其他代碼........ pcTerm.pull()

? Improvement of Push Model?

? ? 針對(duì)Push Model所帶來的問題1,我們可以通過增強(qiáng)sub函數(shù)來解決?

// definition sub(term, aspect){this.subs.push({term: term, aspect: aspect}) } notify(news){for(let sub of this.subs) sub.term.getNews(sub.aspect && sub.aspect(news) || news) }// usage new BusinessNewsType().sub(new PCTerm(), (news)=>{ return news.title })? ?針對(duì)問題2,我們可以通過 定時(shí)推送通知 + 溢出通知 的方式解決,不過具體還是看業(yè)務(wù)需求咯
constructor(interval = 100, ceiling = 5){this.ceiling = ceilingthis.timer = setInterval(()=>{if (!this.pools.length || !this.subs.length) returnfor(let sub of this.subs)for(let n of news)sub.term.getNews(sub.aspect && sub.aspect(n) || n)}, interval) } notify(news){this.pools.push(news)if (this.pools.length < this.ceiling) returnvar news = this.pools.splice(0, this.pools.length)for(let sub of this.subs)for(let n of news)sub.term.getNews(sub.aspect && sub.aspect(n) || n) }

? Specific Implementation Problems ——?Making sure Subject state is self-consistent before notification

? ? 就是確保Subject狀態(tài)變化完成后,再通知Subscriber。反例如下:

notify(news){for(let sub of this.subs) sub.term.getNews(sub.aspect && sub.aspect(news) || news)// 發(fā)生在通知觀察者之后news.title = 'changed' }

? ? 相當(dāng)于為每次Subject狀態(tài)的整體變化打個(gè)版本號(hào),然后將屬于該版本的Subject狀態(tài)發(fā)送給Subscriber,之后的狀態(tài)變化就屬于下一個(gè)版本了。

?

4. Diff Between Observer Pattern and Pub/Sub Pattern?

? ? 兩者區(qū)別主要體現(xiàn)在以下2點(diǎn)

? ? 1. 耦合度

? ? ? ? Observer Pattern: Subscriber 和 Subject 兩者感知對(duì)方的存在,但不受對(duì)方的具體實(shí)現(xiàn) 和 數(shù)目 所限制 => 弱依賴。關(guān)聯(lián)規(guī)則內(nèi)置在Subscriber 或?Subject中。

? ? ? ? Pub/Sub Pattern: Publisher 和 Subscriber 兩者相互間毫無存在感,通過Message Broker關(guān)聯(lián)兩種角色,并且將關(guān)聯(lián)規(guī)則藏進(jìn)Message Broker中。

? ? 2. 影響范圍

? ? ? ? Observer Pattern作為Design Pattern存在,而Pub/Sub Pattern則作為Architecture Pattern存在,明顯Observer Pattern的影響范圍較小。也就是說在采用Pub/Sub Pattern時(shí),需要更謹(jǐn)慎。

?

5. We Used Observer Pattern Already          ?

? ?其實(shí)我們現(xiàn)在用到很多框架、類庫(kù)均采用了Observer Pattern,如MVC和Event Mechanism等。

? ?MVC中M(odel)作為觀察者,而V(iew)作為被觀察者;

? ?而Event Mechanism則是更為典型的Observer Pattern,C#在語法層面(event關(guān)鍵字),而Java通過內(nèi)置類庫(kù)對(duì)其提供支持。

?

6. Conclusion                        

? ?洋洋灑灑寫了這么多,若有紕漏請(qǐng)大家指正,謝謝!

總結(jié)

以上是生活随笔為你收集整理的Design Pattern: Observer Pattern的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。