vlambda博客
学习文章列表

设计模式:创建型-单例模式

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


单例模式的实现思路


按照单例模式的定义,我们需要思考这样一个问题:如何才能保证一个类仅有一个实例?

一般情况下,当我们创建了一个类(本质是构造函数)后,可以通过new关键字生成任意多的实例对象。像这样:

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

上面我们创建了一个s1对象,又new了一个对象s2,两者是相互独立的对象,各占一块内存空间。而单例模式想做的是,不管我们尝试去创建多少次,它都只给你返回第一次所创建的那唯一的一个实例。


要做到这一点,就需要函数具备判断自己是否已经创建过一个实例的能力。我们现在把这段判断逻辑写成一个静态方法:

class SingleDog { show(){    console.log('我是一个单例对象') }  static getInstance () {    // 判断是否已经new过一个实例    if(!SingleDog.instance){      // 未创建      SingleDog.instance = new SIngleDog()    }    return SingleDog.instance  }}
const s1 = SingleDog.getInstance();const s2 = SingleDog.getInstance();s1 === s2 // true

getInstance的逻辑还可以通过闭包,来实现:

class SingleDog { show(){ console.log('我是一个实例'); }  getInstance () { let instance = null; return function () { if(!instance){ instance = new SingleDog(); } return instance; } }}const s1 = SingleDog.getInstance;const s2 = SingleDog.getInstance;
console.log(s1 === s2); // true


生产实践:Vuex中的单例模式


 近年来,基于Flux架构的状态管理工具层出不穷,其中应用最广泛的要数Vuex和Redux。无论是Vuex还是Redux,他们都实现了一个全局的Store用于存储应用的所有状态。这个store的实现,正是单例模式的典型应用。


理解Vuex中的Store


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注入到Vue实例中,Vuex是一个对象,在内部实现了一个install方法,这个方法在引入时被调用,从而把Store注入到Vue实例里去。也就是说每引入一次,都会给Vue实例注入一个Store。

let Vue // 声明一个vue,类似上面的instanse...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实例中只会拥有一个全局的Store。