观察者模式案例的简单分析
觀察者模式
簡(jiǎn)介
觀察者模式也叫發(fā)布-訂閱模式,其定義如下:定義對(duì)象間一種一對(duì)多的依賴(lài)關(guān)系,使得當(dāng)該對(duì)象狀態(tài)改變時(shí),所有依賴(lài)于它的對(duì)象都會(huì)得到通知,并被自動(dòng)更新。
觀察者模式的通知方式可以通過(guò)直接調(diào)用等同步方式實(shí)現(xiàn)(如函數(shù)調(diào)用,HTTP接口調(diào)用等),也可以通過(guò)消息隊(duì)列異步調(diào)用(同步調(diào)用指被觀察者發(fā)布消息后,必須等所有觀察者響應(yīng)結(jié)束后才可以進(jìn)行接下來(lái)的操作;異步調(diào)用指被觀察者發(fā)布消息后,即可進(jìn)行接下來(lái)的操作)。
簡(jiǎn)單來(lái)說(shuō),就是在軟件設(shè)計(jì)中維護(hù)一個(gè)依賴(lài)列表,當(dāng)任何狀態(tài)發(fā)生改變自動(dòng)通知他們。借用一個(gè)在博客看到的例子,觀察者模式就像報(bào)紙和雜志的訂閱:向某家報(bào)社訂閱報(bào)紙,只要報(bào)社有新的的報(bào)紙出版,就會(huì)給你送來(lái),只要你是他們的客戶(hù),你就會(huì)一直收到新的報(bào)紙。當(dāng)你不想再看報(bào)紙的時(shí)候,可以取消訂閱,他們就不再送新的報(bào)紙過(guò)來(lái)。
只要報(bào)社還一直在運(yùn)營(yíng),就會(huì)一直有人(或單位)向他們訂閱報(bào)紙或取消訂閱報(bào)紙。
特點(diǎn)
對(duì)于一個(gè)大型復(fù)雜的系統(tǒng),觀察者模式可以很好的解決類(lèi)間消息交換的問(wèn)題??偨Y(jié)來(lái)說(shuō),觀察者模式有以下優(yōu)點(diǎn):
- 觀察者和被觀察者之間是抽象耦合的;
- 可以把許多負(fù)責(zé)單一職責(zé)的模塊進(jìn)行觸發(fā),也可以很方便的實(shí)現(xiàn)廣播。
觀察者模式的優(yōu)點(diǎn)有時(shí)候也會(huì)是缺點(diǎn),他可能會(huì)帶來(lái)整體系統(tǒng)效率的浪費(fèi),同時(shí)如果被觀察者之間有依賴(lài)關(guān)系的話(huà),其邏輯關(guān)系的梳理需要費(fèi)一些心思。
案例分析
我在github上看到了一個(gè)同學(xué)做的例子,覺(jué)得還不錯(cuò):一個(gè)模塊加載器的簡(jiǎn)單實(shí)現(xiàn)
這個(gè)案例實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的模塊加載器,其中就用到了觀察者模式。接下來(lái)我們分析一下其中用到的觀察者模式。
對(duì)于Watcher這個(gè)構(gòu)造函數(shù),task是一個(gè)待執(zhí)行的callback,uris是這個(gè)異步callback所依賴(lài)的模塊(地址),dep是一個(gè)訂閱器。$len是依賴(lài)模塊的數(shù)組長(zhǎng)度。如果一個(gè)模塊加載好了,那么通知這個(gè)Watcher,這個(gè)Watcher的$len變量就減一。對(duì)于一個(gè)Watcher,我們不用關(guān)心當(dāng)前到底是哪個(gè)模塊加載好了,反正只能是所有依賴(lài)模塊加載好,這個(gè)task才能被執(zhí)行。所以當(dāng)$len為零的時(shí)候,表面依賴(lài)全部加載好,那么這個(gè)Wathcer就執(zhí)行這個(gè)task。
function Watcher(task, uris, dep, Module){this.$task = task;this.$uris = uris;this.dep = dep;this.$Module = Module;this.modArr = [];this.$len = this.$uris.length; }Watcher每執(zhí)行一次update,this.$len--。當(dāng)為零的時(shí)候,執(zhí)行this.run()方法。this.run()中,如果task是一個(gè)函數(shù),那么執(zhí)行執(zhí)行。因?yàn)樵赿efine函數(shù)中,如果define里面沒(méi)有依賴(lài),就會(huì)將其callback直接放入Watcher。如果有依賴(lài),則會(huì)先創(chuàng)建一個(gè)task對(duì)象,將當(dāng)前define腳本的src存入task,以便觸發(fā)該dep的notify方法。
Watcher.prototype = {update: function () {this.$len--;if (this.$len <= 0) {this.run();}},run: function () {let mod = this.$Module.module,task = this.$task;this.$uris.forEach(uri => {this.modArr.push(mod[uri].obj);});//this.$Module.module[this.dep.depName].obj =if (typeof task == 'function') {task.apply(null, this.modArr);return}let src = task.currentSrc;mod[src].obj = task.callback.apply(null, this.modArr);mod[src].dep.notify();this.dep.removeSub(this);return} };Dep是一個(gè)訂閱器,用一個(gè)訂閱器來(lái)存放一個(gè)模塊,不管define有多深,模塊a依賴(lài)于模塊b,模塊b依賴(lài)于模塊c。當(dāng)模塊c加載好后(約定模塊c是不依賴(lài)于任何其他模塊的),模塊c的訂閱器dep觸發(fā)notify方法,subs里面的Watcher的update方法。
function Dep(depName){this.id = uid++;this.subs = [];this.depName = depName; }Dep.prototype = {/*** 添加訂閱, 將watcher添加進(jìn)數(shù)組subs* @param {Object} task new watcher()*/addSubs: function(task){this.subs.push(task);},/*** 刪除訂閱, 將watcher從數(shù)組subs中刪除* @param {Object} task new watcher()*/removeSub: function(task){let index = this.subs.indexOf(task);(index != -1) && this.subs.splice(index, 1);},/*** 當(dāng)該模塊加載好的時(shí)候, 通知所有依賴(lài)它的task*/notify: function(){this.subs.forEach(task => {task.update();});} };以上就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的模塊加載器。一個(gè)對(duì)象的改變狀態(tài),則所有依賴(lài)于它的對(duì)象都會(huì)得到通知更新。在這個(gè)例子中Watcher跟Dep之間是關(guān)聯(lián)關(guān)系,是抽象耦合的,它們之間形成一條觸發(fā)鏈,依次對(duì)每一個(gè)Dep中的對(duì)象進(jìn)行處理。這樣就很好的解決了對(duì)象之間的通信問(wèn)題。
轉(zhuǎn)載于:https://www.cnblogs.com/luuu/p/9842960.html
總結(jié)
以上是生活随笔為你收集整理的观察者模式案例的简单分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android本地文件点击视频播放器vi
- 下一篇: 数仓:维度建模