美文网首页
3、单例模式

3、单例模式

作者: 懂会悟 | 来源:发表于2023-04-24 08:22 被阅读0次

    一、概念

    保证一个类仅有一个实例,并提供一个访问它的全局访问点,这样的模式就叫做单例模式。

    单例模式是设计模式中相对较为容易理解、容易上手的一种模式,同时因为其具有广泛的应用场景,也是面试题里的常客。

    二、实现思路

    现在我们先不考虑单例模式的应用场景,单看它的实现,思考这样一个问题:如何才能保证一个类仅有一个实例? 一般情况下,当我们创建了一个类(本质是构造函数)后,可以通过new关键字调用构造函数进而生成任意多的实例对象。像这样:

    class SingleDog {
      show() {
        console.log("我是一个单例对象");
      }
    }
    
    const s1 = new SingleDog();
    const s2 = new SingleDog();
    
    // false
    s1 === s2
    

    我们先 new 了一个 s1,又 new 了一个 s2,很明显 s1 和 s2 之间没有任何瓜葛,两者是相互独立的对象,各占一块内存空间。而单例模式想要做到的是,不管我们尝试去创建多少次,它都只给你返回第一次所创建的那唯一的一个实例。
    要做到这一点,就需要构造函数具备判断自己是否已经创建过一个实例的能力。我们现在把这段判断逻辑写成一个静态方法(其实也可以直接写入构造函数的函数体里):

    三、简单demo

    class SingleDog {
      show() {
        console.log("我是一个单例对象");
      }
      static getInstance() {
        // 判断是否已经new过1个实例
        if (!SingleDog.instance) {
          // 若这个唯一的实例不存在,那么先创建它
          SingleDog.instance = new SingleDog();
        }
        // 如果这个唯一的实例已经存在,则直接返回
        return SingleDog.instance;
      }
    }
    
    const s1 = SingleDog.getInstance()
    const s2 = SingleDog.getInstance()
    

    除了以上这种实现方法,也可以利用闭包来实现:

    class SingleDog {
      show() {
        console.log("我是一个单例对象")
      }
    }
    
    SingleDog.getInstance = (function () {
      // 定义自由变量instance,模拟私有变量
      let instance = null
      return function () {
        // 判断自由变量是否为null
        if (!instance) {
          // 如果为null则new出唯一实例
          instance = new SingleDog();
        }
        return instance;
      }
    })()
    
    const res = SingleDog.getInstance()
    console.log(res.show())
    

    四、扩展

    1.Vuex中的单例模式

    Vuex 使用单一状态树,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。 ——Vuex官方文档

    在Vue中,组件之间是独立的,组件间通信最常用的办法是 props(限于父组件和子组件之间的通信),稍微复杂一点的(比如兄弟组件间的通信)我们通过自己实现简单的事件监听函数也能解决掉。

    但当组件非常多、组件间关系复杂、且嵌套层级很深的时候,这种原始的通信方式会使我们的逻辑变得复杂难以维护。这时最好的做法是将共享的数据抽出来、放在全局,供组件们按照一定的的规则去存取数据,保证状态以一种可预测的方式发生变化。于是便有了 Vuex,这个用来存放共享数据的唯一数据源,就是 Store。

    Vuex如何确保Store的唯一性

    我们先来看看如何在项目中引入 Vuex:

    // 安装vuex插件
    Vue.use(Vuex);
    
    // 将store注入到Vue实例中
    new Vue({
      el: "#app",
      store,
    })
    

    通过调用Vue.use()方法,我们安装了 Vuex 插件。Vuex 插件是一个对象,它在内部实现了一个 install 方法,这个方法会在插件安装时被调用,从而把 Store 注入到Vue实例里去。也就是说每 install 一次,都会尝试给 Vue 实例注入一个 Store

    在 install 方法里,有一段逻辑和我们楼上的 getInstance 非常相似的逻辑:

    let Vue // 这个Vue的作用和楼上的instance作用一样
    ...
    
    export function install (_Vue) {
      // 判断传入的Vue实例对象是否已经被install过Vuex插件(是否有了唯一的state)
      if (Vue && _Vue === Vue) {
        if (process.env.NODE_ENV !== 'production') {
          console.error(
            '[vuex] already installed. Vue.use(Vuex) should be called only once.'
          )
        }
        return
      }
      // 若没有,则为这个Vue实例对象install一个唯一的Vuex
      Vue = _Vue
      // 将Vuex的初始化逻辑写进Vue的钩子函数里
      applyMixin(Vue)
    }
    

    以上便是 Vuex 源码中单例模式的实现办法了,套路可以说和我们的getInstance如出一辙。通过这种方式,可以保证一个 Vue 实例(即一个 Vue 应用)只会被 install 一次 Vuex 插件,所以每个 Vue 实例只会拥有一个全局的 Store。

    相关文章

      网友评论

          本文标题:3、单例模式

          本文链接:https://www.haomeiwen.com/subject/ehaeddtx.html