1

模式是什么

设计模式是:在软件设计过程中针对「特定」问题的「简洁而优雅」的解决方案。

在软件开发的历史中,沉淀了一些好的软件设计,而设计模式便是给这些好设计取了个名字。「好的设计」并不是某人发明的。一个稍有经验的程序员也许在不知不觉中数次使用过这些设计模式。

模式的意义

设计模式的意义是让人们写出可复用和可维护性高的程序。

举个例子,假设有一个空房间,我们要日复一日地往里面放一些东西。最简单的办法当然是把这些东西直接扔进去,但是时间久了,就会发现很难从这个房子里找到自己想要的东西,要调整某几样东西的位置也不容易。

所以在房间里做一些柜子也许是个更好的选择,虽然柜子会增加我们的成本,但它可以在维护阶段为我们带来好处。使用这些柜子存放东西的规则,或许就是一种模式。

所有设计模式的实现都遵循一条原则,即「找出程序中变化的地方,并将变化封装起来」。

一个程序的设计总是可以分为可变的部分和不变的部分。当我们找出可变的部分,并且把这些部分封装起来,那么剩下的就是不变和稳定的部分。这些不变和稳定的部分是非常容易复用的。

熟悉这些模式的程序员,对某些模式的理解也形成了条件反射,当合适的场景出现时,他们可以很快地找到某种模式作为解决方案。

我们主要学习以下模式:

  • 单例模式
  • 策略模式
  • 代理模式
  • 发布订阅模式
  • 命令模式
  • 状态模式

单例模式

单例模式的定义是:「保证仅有一个实例,并提供一个访问它的全局访问点」。

单列模式场景

单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如全局缓存、浏览器中的 window 对象等。

举个前端的例子,网页loading图(菊花图)。页面整个生命周期,我们只需要生成一个loading就好了。既简化了逻辑(不必去考虑多个请求打开了多个loading)又减少了dom的创建。

实现单例

javascript中,函数是一等公民,所以例子我都优先使用函数来实现(原书是以面向对象的形式展现)

function generateInstance() {
  return {
    say() {
      console.log('hello')
    }
  }
}

let single = (function() {
  let instance  // 哨兵变量
  return function getSingle() {
    if (!instance) {
    // 如果还没有生成实例,那么生成一个。
      instance = generateInstance()
    }
    return instance
  }
})()

let a = single()
let b = single()
console.log(a === b)  // true

以上就是一个单例的例子了。

我们利用闭包保存了一个哨兵变量,用来判断单例是否生成。

单例模式的优缺点

优点:
  • 应用周期,只需实例化一次,对于生成实例开销大的情况,可以提高性能。
  • 方便管理,确保的所有的引用都是同一个实例。
缺点:
  • 实例储存在闭包,是无法销毁的。

范式

下面是一个生成单例的高阶函数。

var getSingle = function(fn) {
  var result
  return function() {
    return result || (result = fn.apply(this, arguments))
  }
}

// 用法
let singeName = getSingle(() => `hello ${Math.random()}`)
let a = singeName()
let b = singeName()
console.log(a === b) // true

发条橙子
399 声望14 粉丝

我爱吃西瓜