淺談Javascript設計模式之行爲型模式

這是我參與 8 月更文挑戰的第 11 天,活動詳情查看: 8月更文挑戰javascript

前言

命令模式(Command Pattern)

用於將一個請求封裝成一個對象,從而使你可用不一樣的請求對客戶進行參數化,對請求排隊或者記錄請求日誌,以及執行可撤銷的操做。也就是說改模式旨在將函數的調用、請求和操做封裝成一個單一的對象。java

function Command(execute, undo, value) {
    this.execute = execute;
    this.undo = undo;
    this.value = value;
}
var AddCommand = function (value) {
    return new Command(add, sub, value);
};
var SubCommand = function (value) {
    return new Command(sub, add, value);
};
var MulCommand = function (value) {
    return new Command(mul, div, value);
};
var DivCommand = function (value) {
    return new Command(div, mul, value);
};
複製代碼

命令具備如下的優勢:設計模式

  (1)命令模式使新的命令很容易地被加入到系統裏。數組

  (2)容許接收請求的一方決定是否要否決請求。緩存

  (3)能較容易地設計一個命令隊列。markdown

  (4)能夠容易地實現對請求的撤銷和恢復。app

  (5)在須要的狀況下,能夠較容易地將命令記入日誌。函數

解釋器模式(Interpreter Pattern)

解釋器模式用於構造一個簡單的語言解釋器,將字符串按照自定義的方式解釋執行 ,是一種不經常使用的設計模式。除非從事底層開發本身須要去定義較爲複雜的表達式,不然基本上不一樣這個設計模式,並且像不少語言其實都有提供動態代碼的執行或者VM的功能。post

好比實現一個對字符串判斷是不是偶數性能

function Interpreter(str) {
    return Number(str) % 2 !== 0;
}
複製代碼

優勢:

  • 易於擴展和修改文法規則。增長時只須要增長新的終結符表達式,符合開關原則。

缺點:

  • 對於複雜文法難以維護,會充滿非終結表達式。
  • 執行效率低,因爲使用了大量循環和遞歸調用,在解釋複雜句子時速度很慢。

迭代器模式(Iterator Pattern)

基本上是每種語言都會實現的一種模式,提供一種方法順序訪問一個聚合對象中各個元素, 而又無須暴露該對象的內部表示。

function each(arr, fn) {
    for (let item of arr) {
        fn(item)
    }
}
each([1, 2, 3], function(item) {
    console.log(item)
})
複製代碼

中介者模式(Mediator Pattern)

中介者模式主要用於一個系統中存在大量的對象,並且這些大量的對象須要互相通訊,由於兩個對象須要通訊,一個對象必需要持有另外一個對象,這樣就會致使,系統裏,每一個對象都互相引用,會引發混亂,中介者把全部的對象都統一管理起來,其餘的對象經過中介者去和別的對象通訊。

咱們能夠大體看下Vue的實現

Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
    const vm: Component = this

    /*若是是數組的時候,則遞歸$on,爲每個成員都綁定上方法*/
    if (Array.isArray(event)) {
      for (let i = 0, l = event.length; i < l; i++) {
        this.$on(event[i], fn)
      }
    } else {
      (vm._events[event] || (vm._events[event] = [])).push(fn)
      // optimize hook:event cost by using a boolean flag marked at registration
      // instead of a hash lookup
      /*這裏在註冊事件的時候標記bool值也就是個標誌位來代表存在鉤子,而不須要經過哈希表的方法來查找是否有鉤子,這樣作能夠減小沒必要要的開銷,優化性能。*/
      if (hookRE.test(event)) {
        vm._hasHookEvent = true
      }
    }
    return vm
  }

  Vue.prototype.$emit = function (event: string): Component {
    const vm: Component = this
    if (process.env.NODE_ENV !== 'production') {
      const lowerCaseEvent = event.toLowerCase()
      if (lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {
        tip(
          `Event "${lowerCaseEvent}" is emitted in component ` +
          `${formatComponentName(vm)} but the handler is registered for "${event}". ` +
          `Note that HTML attributes are case-insensitive and you cannot use ` +
          `v-on to listen to camelCase events when using in-DOM templates. ` +
          `You should probably use "${hyphenate(event)}" instead of "${event}".`
        )
      }
    }
    let cbs = vm._events[event]
    if (cbs) {
      /*將類數組的對象轉換成數組*/
      cbs = cbs.length > 1 ? toArray(cbs) : cbs
      const args = toArray(arguments, 1)
      /*遍歷執行*/
      for (let i = 0, l = cbs.length; i < l; i++) {
        cbs[i].apply(vm, args)
      }
    }
    return vm
  }
複製代碼

備忘錄模式(Memento Pattern)

備忘錄設計模式很是的適合在緩存還原的場景,就是我把某個狀態數據先作緩存,存於內存或者其餘的媒介中,在切換回來此狀態時直接到緩存中的狀態數據給導出,不須要再一步步的進行new操做,提升對象實體生成的效率,提升工做效率和場景體驗。

好比,實現一個斐波那契數列的求和

function fn(n) {
    if (n < 2) {
        return n;
    }
    return fn(n - 1) + fn(n - 2)
}
複製代碼

當咱們把n稍調大的時候,就能夠發現速度特別慢,甚至會爆棧。緣由是中間存在了大量的重複計算,咱們來經過備忘錄模式作一波優化。

const memento = {};
function fn(n) {
    if (n < 2) {
        return n;
    }
    if (memento[n]) {
        return memento[n]
    }
    memento[n] = fn(n - 1) + fn(n - 2)
    return memento[n]
}
複製代碼

最後打波小廣告,美團校招社招內推,不限部門,不限崗位,不限投遞數量,海量hc,快來快來~

相關文章
相關標籤/搜索