從命令式到響應式 (二)

知識點回顧,上次主要說了函數式和麪向對象,命令式和響應式,push 系統和 pull 系統的差異。在編程範式,風格以外,設計模式也是在程序設計中時時刻刻都在使用的東西,今天主要就討論一下設計模式這個東西。java

什麼是設計模式

模式是一種可複用的解決方案,它有三大好處:程序員

  1. 模式是已經獲得驗證的解決方案,所以咱們能夠在適合的場景中放心的使用它。
  2. 模式很容易被複用,是一種當即可用的解決方案,並且能夠對其適當的修改以知足個性化的需求。
  3. 模式富有表達力,它一般有很良好的結構及已經設置好的表達方案的詞彙,能夠很是輕鬆的表達出程序員的意圖。

其實咱們天天都在接觸模式,從最簡單的facade(外觀模式,jQuery,lodash爲表明)到 singleton,再到MVC,模式能夠說無處再也不,固然還有rxjs中使用觀察者模式等。有模式,就有反模式,既然模式能夠帶來好處,相應的反模式就會帶來壞處,在javaScript中,如下就是咱們常常見到的反模式:angularjs

  1. 在全局上下文中定義大量的變量來污染全局命名空間。這裏的全局咱們應該以相對的思惟考慮,而不是特指window對象。例如:在angularjs 中一個controller 做爲封閉的做用域,對於它內部定義的各類變量來講,這個做用域就是全局的,寫過angularjs的同窗應該遇到過,在一個controller中定義不少的變量,而後隨着功能的增長,愈來愈難以維護。
  2. 修改類的原型,尤爲是Object類,比修改更過份的是直接替換。
  3. 之內聯的形式使用javaScript。
  4. 給setTimeout 或 setInterval傳遞字符串而不是函數,這會觸發內部 eval 的執行。

響應式中的設計模式

觀察者模式

在這種模式中,一個對象維持一系列依賴於它的對象,將有關的狀態變動自動的通知給它們。當咱們再也不但願某個特定的觀察者獲取註冊目標的對象時,它能夠從目標的觀察者列表中移除。代碼以下:編程

觀察者列表類,咱們利用這個類來維護觀察者的增刪改查設計模式

class ObserverList {
    constructor() { };

    list = [];

    add(observer) {
        this.list.push(observer);
    }

    count() {
        return this.list.length;
    }

    get(index) {
        if(index > -1 && index < this.list.length) {
            return this.list[index];
        }else {
            return null;
        }
    }

    indexOf(observer, startIndex) {
        let i = startIndex;

        let pointer = -1;

        while( i< this.list.length) {
            if(this.list[i] === observer) {
                pointer = i;
            }
            i++;
        }

        return pointer;
    }

    removeIndexAt(index) {
        if(index === 0) {
            this.list.shift();
        }else if (index === this.list.length - 1) {
            this.list.pop();
        }
    }
}

主題類,利用這個類來維護一個觀察目標,使用觀察者列表類來維護其本身的觀察者,經過觀察者提供的接口向外發送目標上發生的變化。app

class Subject {
    constructor() {
        this.observers = new ObserverList();
    }

    addObserver(observer) {
        this.observers.add(observer);
    }

    removeObserver(observer) {
        this.observers.removeIndexAt(this.observers.indexOf(observer, 0));
    }

    notify(context) {
        const count = this.observers.count();

        for(let i = 0; i< count; i++) {
            this.observers.get(i).update(context);
        }
    }
}

觀察者類,爲目標發生變化時須要得到通知的對象提供一個更新接口。函數

class Observer {
    constructor() { }

    update() {
      // 獲取通知的接口, 不一樣的observe 能夠針對性的設置更新邏輯
    }
}

而後咱們就能夠利用定義好的這些類,實現一些功能,例如,一個主checkbox,當它的狀態變化時通知頁面上其它的checkbox檢查狀態,代碼大體以下:工具

HTML代碼this

<button id="button">Add Observer</button>
<input id="box" type="checkbox">
<div id="container"></div>

javaScript代碼spa

const box = document.getElementById('box');
const btn = document.getElementById('button');
const container = document.getElementById('container');

// 工具函數
function extend(source, target) {
    for (let key in source) {
        target[key] = source[key];
    }
}

// 利用工具函數來擴展DOM元素
extend(new Subject(), box);

// 將點擊事件通知給觀察者
box.onclick = function {
    box.notify(box.checked);
}

btn.onclick = function addNewObserver() {
    const check = document.createElement('input');

    check.type = 'checkbox';

    extend(new Observer(), check);

    // 重寫自定義的更新行爲
    check.update = (value) => this.checked = value;

    // 爲subject的觀察者列表中添加新的觀察者
    box.addObserver(check);

    // 將觀察者附加到容器上
    container.appendChild(check);
}

發佈/訂閱模式

觀察者模式要求但願接收通知的觀察者必須訂閱內容改變的事件,而發佈/訂閱模式中添加了一個事件通道,此通道介於訂閱者和發佈者之間,這樣設置的主要目的是促進發布者和接收者之間的鬆散耦合,避免訂閱者和發佈者產和直接的聯繫,如圖:

Observer Pattern

/----<--Subscribe--<--\
    Subject             Observer
      \--->--Fire Event-->--/

Publish/Subscribe Pattern

/----<--Subscribe--<--\
    Publisher-->--publish-->---Event Channel         Subscriber
                                    \--->---fire event-->--/

在實際的應用中, 這兩種模式能夠結合使用,它們都鼓勵開發者思考應用程序之間不一樣部分之間的關係,將應用程序分解爲更小,更鬆散耦合的塊以提升代碼的複用。

這兩種模式的優缺點

優勢

  1. 只須要維護各個對象之間的通訊接口的一致性,而無需緊密耦合。
  2. 觀察者和目標之間能夠創建起一種動態的關係,這提供了很大的靈活性,在程序的各部分緊密耦合時,要實現這種動態關係是很是不容易的。

缺點

  1. 在發佈/訂閱模式中,因爲解耦了發佈者和訂閱者,有時會難以保證程序按照咱們的預期進行。例如,發佈者會假設有人在訂閱它們,當訂閱者發生錯誤後,因爲系統的解耦,發佈者並不會看到這一點。
  2. 訂閱者之間很是無視彼此的存在,對於變換髮布者產生的成本視而不見,因爲它們之間動態的關係,難以跟蹤依賴更新。

rxjs的實現就是創建在這兩種模式的基礎之上,預先要了解的基本知識經過這兩篇基本上介紹完了,固然都是蜻蜓點水式的,基中任何一個點拿出來均可以長篇大論,各位若有興趣能夠找資料深刻研究。

圖片描述

相關文章
相關標籤/搜索