前端设计模式指南🎨:单例模式

1,971 阅读4分钟

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

前言

这几天准备面试的过程中,复习到了单例模式。我觉得这是很重要的一环,设计模式更是一种优秀的思想。技术栈学多了会发现,其实贯穿技术始终的永远都是这些优秀的设计思想和更高更妙的框架理念。所以我总结了其中一些设计模式的基本概述和实现方法,想和大家分享一下。如有不妥,请多多指教,不胜感激。

基础概念

单例模式,也叫单子模式,属于创建型模式的一种。

单例模式需要保证在全局拥有一个唯一的实例对象,这样有利于我们调节系统整体。例如,我们的整个系统,有时需要一个唯一的全局变量,用来统一全局的配置和某些通用数据。这种模式有很广泛的实践,如 Vuex中对单例模式的使用。

基本使用

我们可以使用整个模块定义一个对象的方法来使用单例模式这种思想,这也是最简单的使用方法。

const one = {
    fn: () => {
        console.log('wow')
    },
    from:'a',
    num:1
}
export { one }

这样我们在调用这个js文件时,由于全局被一个对象包裹,我们就不必担心由于内部变量与其他变量重名而带来的变量重名或者污染了。

同时,我们也可以通过实例化的方式来使用单例模式。其核心思想在于,每次创建实例,返回的都是同一个实例。这种方式创建实例模式有三种方法。我废话少说,直接上代码:

//一开始就创建一个实例(饿汉模式),之后全部返回这个实例。
function One() {
    if(!One.instance) {
        this.fn = () => {
            console.log('>>>>')
        }
        this.balabala = 'QAQ'
        One.instance = this
    }
    return One.instance
}
​
//调用时才创建一个实例(懒汉模式),之后全部返回这个实例。
function One() {
    if(One.instance) 
        return One.instance
    else {
        this.fn = () => {
            console.log('>>>>')
        }
        this.balabala = 'QAQ'
        One.instance = this
    }
}
​
//class创通过class的静态方法来创建
class One {
    instance = null
    constructor() {
        this.balabala = 'hello',
        this.fn = () => {
            console.log('>>>>')
        }
    }
    static getInstance = () => {
        if(!this.instance) {
            this.instance = new One()
        }
        return this.instance
    }
}
​
//三种方法下的输出结果可以表明不同变量创建的实例都是一个。
const a = new One() //class时直接调用静态方法 One.getInstance() 
const b = new One() //class时直接调用静态方法 One.getInstance()
b.balabala = 'world'
console.log(a) //One { instance: null, balabala: 'world', fn: [Function (anonymous)] }
console.log(b) //One { instance: null, balabala: 'world', fn: [Function (anonymous)] }
console.log(a === b) //true

饱受争议的单例

全局范围内的唯一实例,这种模式优缺点都很明显,这也是它饱受争议的原因。

优点

  • 单例模式的所有实例化都是同一个实例,确保所有的对象访问的是一个。
  • 具有一定的伸缩性,由类自身控制实例化过程。
  • 内存只存在一个对象,节约资源,在频繁的创建和销毁时可以提高系统性能。
  • 避免共享资源对内存的多重占用。

缺点

  • 滥用实例可能会导致单例类过于臃肿,被回收时可能会导致某些状态丢失。
  • 单例类违背了“单一职责”原则。他的职责过重,这其实是一种设计弊端。
  • 多线程问题。在使用Web Worker或者node的多线程时可能会导致多个实例被创建。

总结

总的来说,这种设计模式有利有弊,很多框架都在避免出现单例模式。但同时,也有一些框架通过单例模式来实现更加复杂的功能。相对来说,单例模式更适用于重复访问的模块,保存其缓冲,避免重复调用和加载。部分的模块间交互问题也可以用它来解决。

我认为,一种设计模式更多的是一种设计思想,不应该当作八股文只出现在面试中。我们更应该在实际工作中考虑一些业务是否可以使用或者不适用这种设计模式,以及这样做带来的好处是什么。这才应该是设计模式的初衷。

如果你觉得这篇文章不错,可以评论一下。点赞评论的同学较多,我会继续分享其他的设计模式给大家🥳