单例模式: 全局只允许有一个实例

420 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情

单例模式,即对一个 class 只能创建一个实例。

使用ts实现单例模式

class Singleton {
    // private - 外部无法初始化,即无法使用new Singleton来创建实例
    private constructor() { }

    // 加上private 在外面不能使用Singleton.instance来访问,只能通过Singleton.getInstance来访问实例
    private static instance: Singleton | null

    static getInstance(): Singleton {
        // 这里也可以写 `this.instance`,static下的this指向Singleton本身
        if (Singleton.instance == null) {
            Singleton.instance = new Singleton()
        }
        return Singleton.instance
    }
}

// const s1 = new Singleton() // 直接初始化会报错
// Singleton.instance // 直接访问 instance 也会报错

// 创建实例
const s1 = Singleton.getInstance()
const s2 = Singleton.getInstance()

console.log(s1 === s2) // true

image.png

使用js实现单例模式

使用闭包

function genGetInstance() {
    let instance // 闭包

    class Singleton {}

    return () => {
        if (instance == null) {
            instance = new Singleton()
        }
        return instance
    }
}

const getInstance = genGetInstance()

const s1 = getInstance()
const s2 = getInstance()

使用模块化

let instance // 闭包

class Singleton {}

// 外部只能 import 这个函数
export default () => {
    if (instance == null) {
        instance = new Singleton
    }
    return instance
}

其实使用模块化来实现单例,也是使用了闭包,因为模块化之后也会在模块外包裹一层函数。

登录框: 单例模式

class LoginForm {
  private state: string = 'hide'

  private constructor() {}

  show() {
    if (this.state === 'show') {
      console.log('已经显示了')
      return
    }
    console.log('显示 LoginForm')
    // 操作dom 显示登录框
    // ....
    this.state = 'show'
  }

  hide() {
    if (this.state === 'hide') {
      console.log('已经隐藏了')
      return
    }
    console.log('隐藏 LoginForm')
    // 操作dom 隐藏登录框
    // ....
    this.state = 'hide'
  }

  private static instance: LoginForm | null = null
  static getInstance(): LoginForm {
    if (!this.instance) {
      this.instance = new LoginForm()
    }
    return this.instance
  }
}

const loginForm1 = LoginForm.getInstance()
const loginForm2 = LoginForm.getInstance()

前端用到严格的单例模式并不多,但单例模式的思想到处都有:

  • 自定义事件 eventBus 全局只有一个
  • Vuex Redux store 全局只有一个