浅谈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,快来快来~

相关文章
相关标签/搜索