JavaScript 設計模式系列 - 觀察者模式

乘風gg發表於2017-05-16

本系列教程不會講得特別深,通過案例,就帶個入門,面試的時候,被問到能答出個所以來,在實際運用中,能把複雜的問題簡單化就夠了。

概要:

大家應該經常聽到工廠模式,單體模式,但是,可能大家可能第一次聽說觀察者模式,所以我設計模式系列第一篇就來講講觀察者模式。相信大家都用過滑鼠懸停,按鍵等事件,其實他們就是觀察者模式的例子。說重點,這種模式的實質就是你可以對程式中的某個物件的狀態進行觀察,並且在其發生改變時能夠得到通知

角色:

觀察者模式中存在兩種角色:觀察者和被觀察者,也可以叫做釋出者和訂閱者。

作用:

例如,你在你每個階段,進行到一定階段的時候,就要做一些事情,就可以利用觀察者模式做一些相應的處理,不過多解釋了。

詳解:

觀察者模式中,並不是一個物件呼叫另一個物件的方法,而是一個物件訂閱另一個物件的特定活動並在狀態改變後獲得通知。當發生了一個重要的事件時,釋出者將會通知所有訂閱者並且可能經常以事件物件的形式傳遞訊息。

示例

為了加深理解,讓我們來看一個具體的例子,有三個報紙出版社,報社一、報社二、報社三,有兩個訂報人,分別是:訂閱者1,訂閱者2。在這裡出版社就是被觀察者,訂報人就是觀察者

被觀察者
    //觀察者模式:對程式中某一個物件的進行實時的觀察,當該物件狀態發生改變的時候 進行通知
    //被觀察者
    var Publish = function (name) {
        this.name = name;
        this.subscribers = []//陣列中存著所有的訂閱者(出版社名單),陣列的元素都是函式型別
    }
    //publish的例項物件去釋出訊息的方法
    Publish.prototype.deliver = function (news) {
        var publish = this;//this就代表報社
        this.subscribers.forEach(function (item) {
            //迴圈subscribers陣列中所有的訂報人,為他們釋出內容。
            item(news,publish);//每個訂閱者都收到了新聞(news),還有來自哪家報刊
        })
        return this;//為了方便,採用鏈式呼叫。
    }複製程式碼
觀察者

訂閱功能

    //訂閱者的方法,每一個訂閱者都是一個函式,在函式原型上擴充套件一個方法
    Function.prototype.subscribe = function (publish) {//出版社形參
        var sub = this;//取得當前訂閱者這個人
        //不能同時訂一家出版社同一份報紙,沒意義
        //publish.subscribers//張三,李四,王五,名字可能重複
        //publish.subscribers陣列裡面有的人,不能再訂閱
        //我們使用ecma5裡面的some方法,迴圈遍歷陣列的每一個元素,執行一個函式,如果有相同的名字則返回true,不相同則返回false
        var alreadExists = publish.subscribers.some(function (item) {
            return item ===sub;
        })
        //如果出版社名單沒有這個人,則加入其中
        if(!alreadExists){
            publish.subscribers.push(sub);
        }
        return this;//為了方便,採用鏈式呼叫。
    }複製程式碼

取消訂閱

                //具體的一個訂閱者去取消訂閱報紙的方法
                Function.prototype.unsubscribe = function(publish){
                    var sub = this;//取得當前訂閱者這個人
                    // filter (過濾函式:迴圈便利陣列的每一個元素,執行一個函式如果不匹配,則刪除該元素)
                    publish.subscribers = publish.subscribers.filter(function(item){
                        return item !== sub ;
                    });
                    return this;//為了方便,採用鏈式呼叫。
                };複製程式碼

好了,上面就已經做好了基本的準備的,我們來做個小demo

    //例項化釋出者物件(報社物件)
        var pub1 = new Publish('報社一');
        var pub2 = new Publish('報社二');
        var pub3 = new Publish('報社三');

     //觀察者
        var sub1 = function (news,pub) {
            console.log(arguments);
            document.getElementById('sub1').innerHTML +=pub.name+ news +'\n'
        }
        var sub2 = function (news,pub) {
            document.getElementById('sub2').innerHTML += pub.name+news+'\n'
        }
        var p1 = document.getElementById('pub1')
        var p2 = document.getElementById('pub2')
        var p3 = document.getElementById('pub3')
        //執行訂閱方法
        sub1.subscribe(pub1).subscribe(pub2).subscribe(pub3)
        sub2.subscribe(pub1).subscribe(pub2).subscribe(pub3)

        //事件繫結
        p1.onclick = function () {
            pub1.deliver(document.getElementById('text1').value,pub1);
        }
        p2.onclick = function () {
            pub2.deliver(document.getElementById('text2').value,pub2);
        }
        p3.onclick = function () {
            pub3.deliver(document.getElementById('text3').value,pub3);
        }

        sub1.unsubscribe(pub1); //取消訂閱複製程式碼

我們來看看html程式碼段

<div class="col-lg-8">
    <div class="input-group">
      <span id="pub1" class="input-group-addon">
        報社一
      </span>
        <input v-model="user.name" type="text" class="form-control"  id="text1">
    </div>
</div>
<div class="col-lg-8">
    <div class="input-group">
      <span id="pub2" class="input-group-addon">
        報社二
      </span>
        <input v-model="user.name" type="text" class="form-control"  id="text2">
    </div>
</div>
<div class="col-lg-8">
    <div class="input-group">
      <span id="pub3" class="input-group-addon">
        報社三
      </span>
        <input v-model="user.name" type="text" class="form-control"  id="text3">
    </div>
</div>

<div class="col-lg-8">
    訂閱者一
    <textarea id="sub1" class="form-control" rows="5"></textarea>
    訂閱者二:
    <textarea id="sub2"class="form-control" rows="5"></textarea>
</div>複製程式碼

不知道你們看懂了嗎?沒看懂可以隨時留言,後續會出這一系列關於js設計模式的文章,大概有十章左右,包括單體模式,外觀模式,中介者模式等等,由簡單到難(歡迎留言這一篇看的感受),所以歡迎大家指正,批評,督促。
github原始碼地址:github.com/Faithree/js…
參照案例書籍javascript模式

點贊是我的最大支援和鼓勵

相關文章