JavaScript設計模式之觀察者模式(學習筆記)

來源:互聯網
上載者:User

JavaScript設計模式之觀察者模式(學習筆記)
設計模式(Design Pattern)對於軟體開發來說其重要性不言而喻,代碼可複用、可維護、可擴充一直都是軟體工程中的追求!對於我一個學javascript的人來說,理解設計模式似乎有些困難,對僅切圖、做少量互動效果的FE甚至可能不會用到,但是當你開始使用Angular/Backbone等架構的時候,就無法避免設計模式、MVC/MVVM這些東西了(反正我是傷腦筋)。 我學設計模式是剛開始接觸編程大概三個月的時候,看一本書《大話設計模式》,裡面用C#語言來寫,我很無語,因為強型別的程式設計語言對於我這種寫弱類型的毛頭小子來說,似乎又有困難啊,於是我就學C#基礎文法規則去了。。。今年年初我又學了JAVA的基礎文法規則。。。然而我的初衷已經被拋棄在一旁,落上了厚厚的灰層。對於自學編程的我來說,不知道學習編程的先後順序似乎吃虧不少,但是總要有開頭的! 以上可直接跳過 先來說一下我對“觀察者模式”的個人理解:觀察者模式又稱“發布-訂閱(Publish/Subscribe)模式”,發布與訂閱顯然是兩個不同對象的功能,比如RSS。知乎是一個發行者(發布一些對某方面問題的高贊同解答),我作為一個訂閱者(在我的郵箱裡面訂閱了知乎的相關發布內容),我的同事以及我的老闆都訂閱了知乎,所以在這個模型中,有一個發行者,有三個訂閱者。 在具體編程中,發行者有了新的內容,需要向訂閱者推送資料,那麼新的內容(state)、訂閱者有哪些(observers)就是發行者需要包含的東西,誰訂閱了、誰退訂了則要對發行者中的訂閱者列表進行更新。以下是發行者的相關資訊代碼解讀:  

//發行者        function Publisher(){            this.observers = [];            this.state = "";        }        Publisher.prototype.addOb=function(observer){            var flag = false;            for (var i = this.observers.length - 1; i >= 0; i--) {                if(this.observers[i]===observer){                    flag=true;                                }            };            if(!flag){                this.observers.push(observer);            }            return this;        }        Publisher.prototype.removeOb=function(observer){            var observers = this.observers;            for (var i = 0; i < observers.length; i++) {                if(observers[i]===observer){                    observers.splice(i,1);                }            };            return this;        }        Publisher.prototype.notice=function(){            var observers = this.observers;            for (var i = 0; i < observers.length; i++) {                    observers[i].update(this.state);            };        } 

 

 以上在遍曆observers數組的時候,可以使用數組類的filter、forEach等新特性來處理。第三個notice函數表示發行者有了新東西,然後對訂閱者列表中的所有人通知他們我有新內容(state)了,你們拿去更新你們的郵箱吧。這裡把內容傳遞給了每一個訂閱者的update更新功能。 那麼訂閱者呢?訂閱者很簡單,只需要具有一個update功能即可(每一個訂閱者update可能不一樣,比如我是放進郵箱了,我的同事則將訂閱的拿來,並且順便把舊的刪掉了,我的上司則將資料轉寄到Gmail去了)。下面是訂閱者相關資訊代碼解讀:  
//訂閱者        function Subscribe(){            this.update = function(data){                  console.log(data);            };        } 

 

 實際上,因為每一個訂閱者都有這個update,所以我們通常應該將其添加到構造器的原型上面,當對這個預設的update功能不滿足要求的時候,可以為每一個訂閱者的執行個體設定單獨的update,比如將這個data發送給別人。最後咱們看看怎麼應用。  
//實際應用        var oba = new Subscribe(),            obb = new Subscribe();        var pba = new Publisher();        pba.addOb(oba);        pba.addOb(obb);        oba.update = function(state){            console.log(state+"hello!");        }        obb.update = function(state){            console.log(state+"world!");        }        pba.state = "open ";        pba.notice(); 

 

 大家看到,我們在最後對發行者手動設定了它的內容(state)並且要求他發出通知(notice)。在實際項目中,發行者的內容可能是從後台擷取的也可能是從前台某地方輸入的。然而發行者每次更新內容後又要手動調用通知是不是有點多餘呢?既然更新了內容那就肯定要通知別人了啊。那我們就把內容的更新與發出通知進行綁定好了,看下面的代碼:  
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Document</title></head><body>    <script type="text/javascript">        //發行者        function Publisher(){            this.observers = [];            var state = "";     //讓該內容不能直接存取            //新增兩個對於state的操作 擷取/更新            this.getState=function(){                return state;            }            this.setState=function(value){                state = value;                this.notice();            }        }        Publisher.prototype.addOb=function(observer){            var flag = false;            for (var i = this.observers.length - 1; i >= 0; i--) {                if(this.observers[i]===observer){                    flag=true;                                }            };            if(!flag){                this.observers.push(observer);            }            return this;        }        Publisher.prototype.removeOb=function(observer){            var observers = this.observers;            for (var i = 0; i < observers.length; i++) {                if(observers[i]===observer){                    observers.splice(i,1);                }            };            return this;        }        Publisher.prototype.notice=function(){            var observers = this.observers;            for (var i = 0; i < observers.length; i++) {                    observers[i].update(this.getState()); //擷取發行者的內容            };        }        //訂閱者        function Subscribe(){            this.update = function(data){                  console.log(data);            };        }        //實際應用        var oba = new Subscribe(),            obb = new Subscribe();        var pba = new Publisher();        pba.addOb(oba);        pba.addOb(obb);        oba.update = function(state){            console.log(state+"hello!");        }        obb.update = function(state){            console.log(state+"world!");        }        pba.setState("open "); //發行者更新了內容    </script></body></html>

 

  對於以上的內容,或許並沒有跟我們的項目中實際出現的問題有關,那我們就來代入這種設計模式,做一個例子:三個文字框ABC,其中A可編輯,B與C不可編輯且B的值是A的值加上尾碼"@w3c.com",C的值是A的值加上首碼"ID-"。  
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Document</title></head><body>    <div>        <label>使用者名稱稱:<input type="text" id="pba" placeholder="請輸入使用者名稱稱" /></label><br /><br />        <label>產生郵箱:<input type="text" id="oba" readonly /></label>        <label>產生ID:<input type="text" id="obb" readonly /></label>    </div>    <script type="text/javascript">        //發行者        function Publisher(obj){            this.observers = [];            var state = obj.value;     //讓該內容不能直接存取            //新增兩個對於state的操作 擷取/更新            this.getState=function(){                return state;            }            this.setState=function(value){                state = value;                this.notice();            }            this.obj = obj;        }        Publisher.prototype.addOb=function(observer){            var flag = false;            for (var i = this.observers.length - 1; i >= 0; i--) {                if(this.observers[i]===observer){                    flag=true;                                }            };            if(!flag){                this.observers.push(observer);            }            return this;        }        Publisher.prototype.removeOb=function(observer){            var observers = this.observers;            for (var i = 0; i < observers.length; i++) {                if(observers[i]===observer){                    observers.splice(i,1);                }            };            return this;        }        Publisher.prototype.notice=function(){            var observers = this.observers;            for (var i = 0; i < observers.length; i++) {                    observers[i].update(this.getState());            };        }        //訂閱者        function Subscribe(obj){            this.obj = obj;            this.update = function(data){                this.obj.value = data;            };        }        //實際應用        var oba = new Subscribe(document.querySelector("#oba")),            obb = new Subscribe(document.querySelector("#obb"));        var pba = new Publisher(document.querySelector("#pba"));        pba.addOb(oba);        pba.addOb(obb);        oba.update = function(state){            this.obj.value = state+"@w3c.com";        }        obb.update = function(state){            this.obj.value = "ID-"+state;        }        pba.obj.addEventListener('keyup',function(){            pba.setState(this.value);        });            </script></body></html>

 

  在《大話設計模式》一書中,提到類似的情況:如果針對發行者內容而訂閱者要做不同的事情呢?比如一個按鈕和三個矩形,點擊按鈕的時候,第一個矩形增加寬度,第二個矩形增加高度,第三個矩形則變成圓角矩形又該怎麼做呢?當然我們可以在三個矩形的update內部寫具體的實現代碼,但是這update豈不是沒有一個具體的功能描述了嗎?該書中用“事件委託”解決了這個問題(此處事件委託和DOM中的事件委託應該是兩碼事),我個人理解這個“事件委託”在javascript中可以用一個數組表示,然后里面放各個訂閱者的不同名字的update,然後一一調用。 在《javascript設計模式》一書中,關於觀察者模式的實現也是採用”推“這種方式,章節的最後反問到如何?”拉“這種方式呢? 我個人理解:發行者推送資料的時候有強制性,促使訂閱者更新(update),然而在”拉“這種模式中,發行者本身僅僅包含最新的內容,沒有通知(notice)沒有訂閱者列表,當訂閱者需要得到資料的時候在其對應的update方法裡面傳入發行者對象即可。小白之見,請對該模式有不同理解的道友多多指正。o(∩_∩)o 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.