JavaScript設(shè)計(jì)模式之觀察者模式

嗯~~~

開(kāi)門見(jiàn)山卸奉,這次我也就不賣關(guān)子了钝诚,今天我們就來(lái)聊一聊 JavasSript 設(shè)計(jì)模式中的 觀察者模式 颖御,首先我們來(lái)認(rèn)識(shí)一下,什么是觀察者模式?

什么是觀察者模式潘拱?

觀察者模式(Observer)

通常又被稱為 發(fā)布-訂閱者模式消息機(jī)制疹鳄,它定義了對(duì)象間的一種一對(duì)多的依賴關(guān)系,只要當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí)芦岂,所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新瘪弓,解決了主體對(duì)象與觀察者之間功能的耦合,即一個(gè)對(duì)象狀態(tài)改變給其他對(duì)象通知的問(wèn)題禽最。

單純的看定義腺怯,對(duì)于前端小伙伴們,可能這個(gè)概念還是比較模糊川无,對(duì)于觀察者模式還是一知半解呛占,ok,那我就來(lái)看個(gè)生活中比較貼切的例子懦趋,相信你立馬就懂了~

生活中的觀察者模式

每次小米出新款手機(jī)都是熱銷晾虑,我看中了小米3這款手機(jī),想去小米之家購(gòu)買仅叫,但是到店后售貨員告訴我他們這款手機(jī)很熱銷帜篇,他們已經(jīng)賣完了,現(xiàn)在沒(méi)有貨了诫咱,那我不可能每天都跑過(guò)來(lái)問(wèn)問(wèn)吧笙隙,這樣很耽誤時(shí)間的,于是我將我的手機(jī)號(hào)碼留給銷售小姐姐坎缭,如果他們店里有貨逃沿,讓她打電話通知我就好了,這樣就不用擔(dān)心不知道什么時(shí)候有貨幻锁,也不需要天天跑去問(wèn)了凯亮,如果你已經(jīng)成功買到了手機(jī)呢,那么銷售小姐姐之后也就不需要通知你了~

這樣是不是清晰了很多~諸如此類的案例還有很多哄尔,我也就不在贅述了假消。

觀察者模式的使用

不瞞你說(shuō),我敢保證岭接,過(guò)來(lái)看的每個(gè)人都使用過(guò)觀察者模式~

什么富拗,你不信?

那么來(lái)看看下面這段代碼~

    document.querySelector('#btn').addEventListener('click',function () {
        alert('You click this btn');
    },false)

怎么樣鸣戴,是不是很眼熟啃沪!

沒(méi)錯(cuò),我們平時(shí)對(duì) DOM 的事件綁定就是一個(gè)非常典型的 發(fā)布-訂閱者模式 窄锅,這里我們需要監(jiān)聽(tīng)用戶點(diǎn)擊按鈕這個(gè)動(dòng)作创千,但是我們卻無(wú)法知道用戶什么時(shí)候去點(diǎn)擊,所以我們訂閱 按鈕上的 click 事件,只要按鈕被點(diǎn)擊時(shí)追驴,那么按鈕就會(huì)向訂閱者發(fā)布這個(gè)消息械哟,我們就可以做對(duì)應(yīng)的操作了。

除了我們常見(jiàn)的 DOM 事件綁定外殿雪,觀察者模式應(yīng)用的范圍還有很多~

比如比較當(dāng)下熱門 vue 框架暇咆,里面不少地方都涉及到了觀察者模式,比如:

數(shù)據(jù)的雙向綁定

利用 Object.defineProperty() 對(duì)數(shù)據(jù)進(jìn)行劫持丙曙,設(shè)置一個(gè)監(jiān)聽(tīng)器 Observer爸业,用來(lái)監(jiān)聽(tīng)所有屬性,如果屬性上發(fā)上變化了亏镰,就需要告訴訂閱者 Watcher 去更新數(shù)據(jù)沃呢,最后指令解析器 Compile 解析對(duì)應(yīng)的指令,進(jìn)而會(huì)執(zhí)行對(duì)應(yīng)的更新函數(shù)拆挥,從而更新視圖薄霜,實(shí)現(xiàn)了雙向綁定~

子組件與父組件通信

Vue 中我們通過(guò) props 完成父組件向子組件傳遞數(shù)據(jù),子組件與父組件通信我們通過(guò)自定義事件即 $on,$emit來(lái)實(shí)現(xiàn)纸兔,其實(shí)也就是通過(guò) $emit 來(lái)發(fā)布消息惰瓜,并對(duì)訂閱者 $on 做統(tǒng)一處理 ~

ok,說(shuō)了這么多汉矿,該我們自己露一手了崎坊,接下來(lái)我們來(lái)自己創(chuàng)建一個(gè)簡(jiǎn)單的觀察者~

創(chuàng)建一個(gè)觀察者

首先我們需要?jiǎng)?chuàng)建一個(gè)觀察者對(duì)象,它包含一個(gè)消息容器和三個(gè)方法洲拇,分別是訂閱消息方法 on , 取消訂閱消息方法 off 奈揍,發(fā)送訂閱消息 subscribe

    const Observe = (function () {
        //防止消息隊(duì)列暴露而被篡改赋续,將消息容器設(shè)置為私有變量
        let __message = {};
        return {
            //注冊(cè)消息接口
            on : function () {},
            //發(fā)布消息接口
            subscribe : function () {},
            //移除消息接口
            off : function () {}
        }
    })();

好的男翰,我們的觀察者雛形已經(jīng)出來(lái)了,剩下的就是完善里面的三個(gè)方法~

注冊(cè)消息方法

注冊(cè)消息方法的作用是將訂閱者注冊(cè)的消息推入到消息隊(duì)列中纽乱,因此需要傳遞兩個(gè)參數(shù):消息類型和對(duì)應(yīng)的處理函數(shù)蛾绎,要注意的是,如果推入到消息隊(duì)列是如果此消息不存在鸦列,則要?jiǎng)?chuàng)建一個(gè)該消息類型并將該消息放入消息隊(duì)列中租冠,如果此消息已經(jīng)存在則將對(duì)應(yīng)的方法突入到執(zhí)行方法隊(duì)列中。

    //注冊(cè)消息接口
    on: function (type, fn) {
        //如果此消息不存在薯嗤,創(chuàng)建一個(gè)該消息類型
        if( typeof __message[type] === 'undefined' ){
            // 將執(zhí)行方法推入該消息對(duì)應(yīng)的執(zhí)行隊(duì)列中
            __message[type] = [fn];
        }else{
            //如果此消息存在顽爹,直接將執(zhí)行方法推入該消息對(duì)應(yīng)的執(zhí)行隊(duì)列中
            __message[type].push(fn);
        }
    }

發(fā)布消息方法

發(fā)布消息,其功能就是當(dāng)觀察者發(fā)布一個(gè)消息是將所有訂閱者訂閱的消息依次執(zhí)行骆姐,也需要傳兩個(gè)參數(shù)镜粤,分別是消息類型和對(duì)應(yīng)執(zhí)行函數(shù)時(shí)所需要的參數(shù)捏题,其中消息類型是必須的。

    //發(fā)布消息接口
    subscribe: function (type, args) {
        //如果該消息沒(méi)有注冊(cè)繁仁,直接返回
        if ( !__message[type] )  return;
        //定義消息信息
        let events = {
            type: type,           //消息類型
            args: args || {}       //參數(shù)
        },
        i = 0,                         // 循環(huán)變量
        len = __message[type].length;   // 執(zhí)行隊(duì)列長(zhǎng)度
        //遍歷執(zhí)行函數(shù)
        for ( ; i < len; i++ ) {
            //依次執(zhí)行注冊(cè)消息對(duì)應(yīng)的方法
            __message[type][i].call(this,events)
        }
    }

移除消息方法

移除消息方法涉馅,其功能就是講訂閱者注銷的消息從消息隊(duì)列中清除归园,也需要傳遞消息類型和執(zhí)行隊(duì)列中的某一函數(shù)兩個(gè)參數(shù)黄虱。這里為了避免刪除是,消息不存在的情況庸诱,所以要對(duì)其消息存在性制作校驗(yàn)捻浦。

    //移除消息接口
    off: function (type, fn) {
        //如果消息執(zhí)行隊(duì)列存在
        if ( __message[type] instanceof Array ) {
            // 從最后一條依次遍歷
            let i = __message[type].length - 1;
            for ( ; i >= 0; i-- ) {
                //如果存在改執(zhí)行函數(shù)則移除相應(yīng)的動(dòng)作
                __message[type][i] === fn && __message[type].splice(i, 1);
            }
        }
    }

ok,到此桥爽,我們已經(jīng)實(shí)現(xiàn)了一個(gè)基本的觀察者模型朱灿,接著就是我們大顯身手的時(shí)候了~
趕緊拿出來(lái)測(cè)試測(cè)試啊~

大顯身手

首先我們先來(lái)一個(gè)簡(jiǎn)單的測(cè)試,看看我們自己創(chuàng)建的觀察者模式執(zhí)行效果如何钠四?

   //訂閱消息
    Observe.on('say', function (data) {
        console.log(data.args.text);
    })
    Observe.on('success',function () {
        console.log('success')
    });
    
    //發(fā)布消息
    Observe.subscribe('say', { text : 'hello world' } )
    Observe.subscribe('success');  

我們?cè)谙㈩愋蜑?say 的消息中注冊(cè)了兩個(gè)方法盗扒,其中有一個(gè)接受參數(shù),另一個(gè)不需要參數(shù)缀去,然后通過(guò) subscribe 發(fā)布 saysuccess 消息侣灶,結(jié)果跟我們預(yù)期的一樣,控制臺(tái)輸出了 hello world 以及 success ~

看缕碎!我們已經(jīng)成功的實(shí)現(xiàn)了我們的觀察者~ 為自己點(diǎn)個(gè)贊吧褥影!

自定義數(shù)據(jù)的雙向綁定

上面說(shuō)到,vue 雙向綁定是數(shù)據(jù)劫持和發(fā)布訂閱做實(shí)現(xiàn)的咏雌,現(xiàn)在我們借助這種思想凡怎,自己來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的數(shù)據(jù)的雙向綁定~

首先當(dāng)然是要有頁(yè)面結(jié)構(gòu)了,這里不講究什么赊抖,我就隨手一碼了~

<div id="app">
    <h3>數(shù)據(jù)的雙向綁定</h3>
    <div class="cell">
        <div class="text" v-text="myText"></div>
        <input class="input" type="text" v-model="myText" >
    </div>
</div>

相信你已經(jīng)知道了统倒,我們要做到就是 input 標(biāo)簽的輸入,通過(guò) v-text 綁定到類名為 textdiv 標(biāo)簽上~

首先我們需要?jiǎng)?chuàng)建一個(gè)類氛雪,這里就叫做 myVue 吧檐薯。

class myVue{
    constructor (options){
        // 傳入的配置參數(shù)
        this.options = options;
        // 根元素
        this.$el = document.querySelector(options.el);
        // 數(shù)據(jù)域
        this.$data = options.data;
        
        // 保存數(shù)據(jù)model與view相關(guān)的指令,當(dāng)model改變時(shí)注暗,我們會(huì)觸發(fā)其中的指令類更新坛缕,保證view也能實(shí)時(shí)更新
        this._directives = {};
        // 數(shù)據(jù)劫持,重新定義數(shù)據(jù)的 set 和 get 方法
        this._obverse(this.$data);
        // 解析器捆昏,解析模板指令赚楚,并將每個(gè)指令對(duì)應(yīng)的節(jié)點(diǎn)綁定更新函數(shù),添加監(jiān)聽(tīng)數(shù)據(jù)的訂閱者骗卜,一旦數(shù)據(jù)有變動(dòng)宠页,收到通知左胞,更新視圖
        this._compile(this.$el);
    }
}

這里我們定義了 myVue 構(gòu)造函數(shù),并在構(gòu)造方法中進(jìn)行了一些初始化操作举户,上面做了注釋烤宙,這里我就不在贅述,主要來(lái)看里面關(guān)鍵的兩個(gè)方法 _obverse_compile俭嘁。

首先是 _observe 方法躺枕,他的作用就是處理傳入的 data ,并重新定義 datasetget 方法供填,保證我們?cè)?data 發(fā)生變化的時(shí)候能跟蹤到拐云,并發(fā)布通知,主要用到了 Object.defineProperty() 這個(gè)方法近她,對(duì)這個(gè)方法還不太熟悉的小伙伴們叉瘩,請(qǐng)猛戳這里~

_observe

    //_obverse 函數(shù),對(duì)data進(jìn)行處理粘捎,重寫(xiě)data的set和get函數(shù)
    _obverse(data){
        let val ;
        //遍歷數(shù)據(jù)
        for( let key in data ){
            // 判斷是不是屬于自己本身的屬性
            if( data.hasOwnProperty(key) ){
                this._directives[key] = [];
            }
        
            val = data[key];        
            //遞歸遍歷
            if ( typeof val === 'object' ) {
                //遞歸遍歷
                this._obverse(val);
            }
            
            // 初始當(dāng)前數(shù)據(jù)的執(zhí)行隊(duì)列
            let _dir = this._directives[key];
        
            //重新定義數(shù)據(jù)的 get 和 set 方法
            Object.defineProperty(this.$data,key,{
                enumerable: true,
                configurable: true,
                get: function () {
                    return val;
                },
                set: function (newVal) {
                    if ( val !== newVal ) {
                        val = newVal;
                        // 當(dāng) myText 改變時(shí)薇缅,觸發(fā) _directives 中的綁定的Watcher類的更新
                        _dir.forEach(function (item) {
                            //調(diào)用自身指令的更新操作
                            item._update();
                        })
                    }
                }
            })
        }
    }

上面的代碼也很簡(jiǎn)單,注釋也都很清楚攒磨,不過(guò)有個(gè)問(wèn)題就是泳桦,我在遞歸遍歷數(shù)據(jù)的時(shí)候,偷了個(gè)小懶 --咧纠,這里我只涉及到了一些簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)事哭,復(fù)雜的例如循環(huán)引用的這種我沒(méi)有考慮進(jìn)入载矿,大家可以自行補(bǔ)充一下哈~

接著我們來(lái)看看 _compile 這個(gè)方法罩扇,它實(shí)際上是一個(gè)解析器担神,其功能就是解析模板指令,并將每個(gè)指令對(duì)應(yīng)的節(jié)點(diǎn)綁定更新函數(shù)演痒,添加監(jiān)聽(tīng)數(shù)據(jù)的訂閱者亲轨,一旦數(shù)據(jù)有變動(dòng),就收到通知鸟顺,然后去更新視圖變化惦蚊,具體實(shí)現(xiàn)如下:

_compile

_compile(el){
    //子元素
    let nodes = el.children;
    for( let i = 0 ;  i < nodes.length ; i++ ){
        let node = nodes[i];
        // 遞歸對(duì)所有元素進(jìn)行遍歷,并進(jìn)行處理
        if( node.children.length ){
            this._compile(node);
        }
    
        //如果有 v-text 指令 , 監(jiān)控 node的值 并及時(shí)更新
        if( node.hasAttribute('v-text')){
            let attrValue = node.getAttribute('v-text');
            //將指令對(duì)應(yīng)的執(zhí)行方法放入指令集
            this._directives[attrValue].push(new Watcher('text',node,this,attrValue,'innerHTML'))
        }
    
        //如果有 v-model屬性讯嫂,并且元素是INPUT或者TEXTAREA蹦锋,我們監(jiān)聽(tīng)它的input事件
        if( node.hasAttribute('v-model') && ( node.tagName === 'INPUT' || node.tagName === 'TEXTAREA')){
            let _this = this;
            //添加input時(shí)間
            node.addEventListener('input',(function(){
                let attrValue = node.getAttribute('v-model');
                //初始化賦值
                _this._directives[attrValue].push(new Watcher('input',node,_this,attrValue,'value'));
                return function () {
                    //后面每次都會(huì)更新
                    _this.$data[attrValue] = node.value;
                }
            })())
        }
    }
}

上面的代碼也很清晰,我們從根元素 #app 開(kāi)始遞歸遍歷每個(gè)節(jié)點(diǎn)欧芽,并判斷每個(gè)節(jié)點(diǎn)是否有對(duì)應(yīng)的指令莉掂,這里我們只針對(duì) v-textv-model,我們對(duì) v-text 進(jìn)行了一次 new Watcher()千扔,并把它放到了 myText 的指令集里面憎妙,對(duì) v-model 也進(jìn)行了解析库正,對(duì)其所在的 input 綁定了 input 事件,并將其通過(guò) new Watcher()myText 關(guān)聯(lián)起來(lái)厘唾,那么我們就應(yīng)該來(lái)看看這個(gè) Watcher 到底是什么褥符?

Watcher 其實(shí)就是訂閱者,是 _observer_compile 之間通信的橋梁用來(lái)綁定更新函數(shù)抚垃,實(shí)現(xiàn)對(duì) DOM 元素的更新

Warcher

class Watcher{
    /*
    * name  指令名稱喷楣,例如文本節(jié)點(diǎn),該值設(shè)為"text"
    * el    指令對(duì)應(yīng)的DOM元素
    * vm    指令所屬myVue實(shí)例
    * exp   指令對(duì)應(yīng)的值讯柔,本例如"myText"
    * attr  綁定的屬性值抡蛙,本例為"innerHTML"
    * */
    constructor (name, el, vm, exp, attr){
        this.name = name;
        this.el = el;
        this.vm = vm;
        this.exp = exp;
        this.attr = attr;
    
        //更新操作
        this._update();
    }
    
    _update(){
        this.el[this.attr] = this.vm.$data[this.exp];
    }
}

每次創(chuàng)建 Watcher 的實(shí)例护昧,都會(huì)傳入相應(yīng)的參數(shù)魂迄,也會(huì)進(jìn)行一次 _update 操作,上述的 _compile 中惋耙,我們創(chuàng)建了兩個(gè) Watcher 實(shí)例捣炬,不過(guò)這兩個(gè)對(duì)應(yīng)的 _update 操作不同而已,對(duì)于 div.text 的操作其實(shí)相當(dāng)于 div.innerHTML=h3.innerHTML = this.data.myText 绽榛, 對(duì)于 input 相當(dāng)于 input.value=this.data.myText , 這樣每次數(shù)據(jù) set 的時(shí)候湿酸,我們會(huì)觸發(fā)兩個(gè) _update 操作,分別更新 divinput 中的內(nèi)容~

廢話不多說(shuō)灭美,趕緊測(cè)試一下吧~

先初始化一下~

    //創(chuàng)建vue實(shí)例
    const app = new myVue({
        el : '#app' ,
        data : {
            myText : 'hello world'
        }
    })

接著推溃,上圖~

我們順利的實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的雙向綁定,棒棒噠 ~

結(jié)語(yǔ)

現(xiàn)在届腐,是不是已經(jīng)對(duì)觀察者模式有比較深刻的理解了呢铁坎?其實(shí),我這里說(shuō)了這么多犁苏,只是起到了一個(gè)拋磚引玉的作用硬萍,重要的是設(shè)計(jì)思想,要學(xué)會(huì)將這種設(shè)計(jì)思想合理的應(yīng)用到我們實(shí)際的開(kāi)發(fā)過(guò)程中围详,可能過(guò)程會(huì)比較艱難朴乖,但是紙上得來(lái)終覺(jué)淺,絕知此事要躬行啊助赞,大家加油~

哦买羞,對(duì)了,今天 1024 啊 雹食, 大家節(jié)日快樂(lè)哈~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末畜普,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子婉徘,更是在濱河造成了極大的恐慌漠嵌,老刑警劉巖咐汞,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異儒鹿,居然都是意外死亡化撕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門约炎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)植阴,“玉大人,你說(shuō)我怎么就攤上這事圾浅÷邮郑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵狸捕,是天一觀的道長(zhǎng)喷鸽。 經(jīng)常有香客問(wèn)我,道長(zhǎng)灸拍,這世上最難降的妖魔是什么做祝? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮鸡岗,結(jié)果婚禮上混槐,老公的妹妹穿的比我還像新娘。我一直安慰自己轩性,他們只是感情好声登,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著揣苏,像睡著了一般悯嗓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上舒岸,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天绅作,我揣著相機(jī)與錄音,去河邊找鬼蛾派。 笑死俄认,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的洪乍。 我是一名探鬼主播眯杏,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼壳澳!你這毒婦竟也來(lái)了岂贩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤巷波,失蹤者是張志新(化名)和其女友劉穎萎津,沒(méi)想到半個(gè)月后卸伞,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锉屈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年荤傲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颈渊。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡遂黍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出俊嗽,到底是詐尸還是另有隱情雾家,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布绍豁,位于F島的核電站芯咧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏妹田。R本人自食惡果不足惜唬党,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一鹃共、第九天 我趴在偏房一處隱蔽的房頂上張望鬼佣。 院中可真熱鬧,春花似錦霜浴、人聲如沸晶衷。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)晌纫。三九已至,卻和暖如春永丝,著一層夾襖步出監(jiān)牢的瞬間锹漱,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工慕嚷, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哥牍,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓喝检,卻偏偏與公主長(zhǎng)得像嗅辣,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挠说,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1. 觀察者模式介紹 觀察者模式也稱發(fā)布訂閱(publish/subscribe簡(jiǎn)稱Pub/Sub)模式澡谭。這是一種...
    家里有棵核桃樹(shù)閱讀 637評(píng)論 0 5
  • 前言 準(zhǔn)備研究一下MVVM的一些東西,由于MVVM運(yùn)用了觀察者模式的思想损俭,因此翻開(kāi)了《JavaScript設(shè)計(jì)模式...
    Srtian閱讀 6,919評(píng)論 5 8
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理蛙奖,服務(wù)發(fā)現(xiàn)潘酗,斷路器,智...
    卡卡羅2017閱讀 134,599評(píng)論 18 139
  • vue理解淺談 一 理解vue的核心理念 使用vue會(huì)讓人感到身心愉悅,它同時(shí)具備angular和react的優(yōu)點(diǎn)...
    ambeer閱讀 24,103評(píng)論 2 18
  • 前幾天跟朋友聊天囚灼,問(wèn)了一個(gè)問(wèn)題,“男人喜歡什么樣的女人祭衩?”朋友回答灶体,每個(gè)男人喜歡的女人類型不同,但他們都喜歡有女人...
    所未2017閱讀 624評(píng)論 0 0