设计模式:创建型-单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点,这样的模式就叫做单例模式。
单例模式的实现思路
按照单例模式的定义,我们需要思考这样一个问题:如何才能保证一个类仅有一个实例?
一般情况下,当我们创建了一个类(本质是构造函数)后,可以通过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一个唯一的VuexVue = _Vue// 将Vuex的初始化逻辑写进Vue的钩子函数里applyMixin(Vue)}
上面便是Vuex源码中单例模式的实现方法了,套路可以说跟我们的getInstance如出一辙。通过这种方式,可以保证Vue实例中只会拥有一个全局的Store。
