设计模式-单例模式

127 阅读3分钟

定义

保证一个类仅有一个实例,并提供一个访问他的全局方法

优缺点

优点

  1. 资源管理: 确保程序只有一个实例,减少资源消耗和内存占用
  2. 全局访问:单例模式提供了全局唯一访问方式,使得程序在任何地方都能轻松的访问到此实例

缺点

  1. 全局访问:这个特点既是他的优点也是他的缺点,使用不当会导致程序意外发生
  2. 耦合性高:对象的创建和使用紧密地耦合在一起,可能导致其他模块对单例对象的依赖增加,降低了系统的可维护性和可扩展性

应用场景

全局缓存(如localforage实现,他是通过class实现,但是导出的是他的实例)、浏览器中的window、登录验证弹窗等

实现

饿汉式(指实例在类创建的时候就已经创建)

 class SingletonPattern{
     // 私有变量,存放实例
     static #instance = new SingletonPattern()
     constrctor(){}
     // 公共方法访问实例
     static getInstance(){
         return this.#instance
     }
 }

 const ins1 = SingletonPattern.getInstance()
 const ins2 = SingletonPattern.getInstance()
 console.log(ins1 === ins2) // true

懒汉式(惰性单例,在真正使用的时候才去创建实例)


 class SingletonPattern{
     // 私有变量,存放实例
     static #instance
     constrctor(){}
     // 公共方法访问实例
     static getInstance(){
         if (!this.#instance){
             this.#instance = new SingletonPattern()
         }
         return this.#instance
     }
 }

 const ins1 = SingletonPattern.getInstance()
 const ins2 = SingletonPattern.getInstance()
 console.log(ins1 === ins2) // true

优化

当前的单例模式是不透明的,使用方必须要知道当前类是单例类,不能像一般使用new创建实例,有没有一种方法可以既能让他像传统使用一样,又让他是单例。答案是有的,通过代理来实现单例模式,将创建和使用对象隔离开来。

// 业务类,具体业务的实现
class A {
    options
    constrctor(options){
        this.options = options
    }
}

// 代理类 这里需要使用函数的方式而不是class方式创建类
const ProxySingletonA = (function(Constructor){
    let _instance
    return function (...args){
        if (!_instance){
            _instance = new Constructor(args)
        }
        return instance
    }
})(A)

const a = new ProxySingleA('a')
const b = new ProxySingleA('b')
consle.log(a===b) // true

在这种实现方式里面我们通过一个代理类实现了,通过new来实现单例模式,并且将业务和管理单例分开了,从而获得更好的维护和扩展

JavaScript里的单例

对于JavaScript来说单例模式可以说是随处可见,不一定就是传统的这种实现方式。

单例模式的核心是确保只有一个实例,并提供全局访问

这给了我们启发,全局对象是不是也可以当做单例模式来使用如:var a = {}通过这种方式创建对象,对象确实是唯一的,如果它被声明在全局作用域中,这就满足了单例模式的两个基本条件。不过全局变量谨慎使用,可以使用命名空间,闭包等来规避。

ESModule单例

现如今我们更多的使用ESModule来编写我们的代码,那么单例模式也可以是这样的:

// SingletonPattern.js
class SingletonPattern{
    constrctor(){}
    // 以下是业务代码
}
export default new SingletonPattern()

这个SingletonPattern.js文件对外暴露的就是SingletonPattern的一个实例,我们在其他文件引入的时候始终引入的都是这个实例,也就满足单例的特性。这种方法在一些库中很常见,如:localforage,在我们自己编写一些库的时候也可以采用这种方式。

参考文献

《Javascript设计模式与开发实践》