javascript设计模式之单例模式

3 篇文章 0 订阅
2 篇文章 0 订阅

一 什么是单例模式

单例模式之所以这么叫,是因为它限制一个类只能有一个实例化对象。经典的实现方式是,创建一个类,这个类包含一个方法,这个方法在没有对象存在的情况下,将会创建一个新的实例对象。如果对象存在,这个方法只是返回这个对象的引用

二 实现一个单例模式

2.1 ES6的class写法

class Singleton {
      static instance = null

       constructor() {
           this.num = Math.random()
       }

       getNum() {
           return this.num
       }

       static getInstance() {
           if(!Singleton.instance) {
               Singleton.instance = new Singleton()
           }
           return Singleton.instance
       }
   }

   let singleA = Singleton.getInstance()
   let singleB = Singleton.getInstance()

   console.log(singleA.getNum() === singleB.getNum())  //true

上面的Singleton.getInstance()永远获取到的都是同一个实例,他们初始化的num的值一定都是相同的,所以两个单例通过getNum()方法获取的值也是相等的.但是单例模式下初始值都是固定的,有的时候我们需要改变num的初始值,那么可以做如下改变:

class Singleton {
     static instance = null

     constructor() {
         this.num = Math.random()
     }

     getNum() {
         return this.num
     }

     setNum(val) {
         this.num = val
         //返回的this指向当前的单例
         return this
     }

     static getInstance() {
         if(!Singleton.instance) {
             Singleton.instance = new Singleton()
         }
         return Singleton.instance
     }
 }

 let singleA = Singleton.getInstance()
 let singleB = Singleton.getInstance()

 //改变singleB单例的初始值
 let numB = singleB.setNum(10).getNum()
 let numA = singleA.getNum()

 console.log(numA,numB) // 10 10 

虽然改变了初始值,但是还是会影响到创建的多个单例上singleA,singleB.

2.1.1 语法缺陷

let singleA = Singleton.getInstance()
//修改了这个单例
Singleton.instance = null

let singleB = Singleton.getInstance()

console.log(singleA.getNum() === singleB.getNum())  //false

这里我们修改了Singleton.instance的值造成后面生成的单例singleB与singleA不在是同意了单例了,为了解决这个问题,我们利用Symbol来实现:

const instance = Symbol.for('instance');
class Singleton {
      static [instance] = null
   	  .......
   	  static getInstance() {
	    if(!Singleton[instance]) {
	        Singleton[instance] = new Singleton()
	    }
	    return Singleton[instance]
	}
}
let singleA = Singleton.getInstance()
let singleB = Singleton.getInstance()

console.log(singleA.getNum() === singleB.getNum())  //true

这样就可以避免instance被误写,但是还是可以被改写:

Singleton[instance] = null
let singleB = Singleton.getInstance()

console.log(singleA.getNum() === singleB.getNum())  //false

如果键名使用Symbol方法生成,那么外部将无法引用这个值,当然也就无法改写:

const instance = Symbol.for('instance');
class Singleton {
	XXXXX(后面代码一样)
}

其中的区别是:

Symbol.for()与Symbol()这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。比如,如果你调用Symbol.for(“cat”)30 次,每次都会返回同一个 Symbol 值,但是调用Symbol(“cat”)30 次,会返回 30 个不同的 Symbol 值。

这里每次Singleton.getInstance()都会重新创建一个新的symbol的instance,所以每次都不同

2.2 ES5的写法:

var MySingleton = (function() {
     let instance = null
     function Singleton() {
         this.num = Math.random()
     }

     Singleton.prototype.getNum = function () {
         return this.num
     }

     return {
         getInstance: function() {
             if(!instance) {
                 instance = new Singleton()
             }
             return instance
         }
     }
 })()

 let singleA = MySingleton.getInstance()
 let singleB = MySingleton.getInstance()

 //改变singleB单例的初始值
 let numB = singleB.getNum()
 let numA = singleA.getNum()

 console.log(numA === numB)  //true

三 总结

1. 单例模式,永远指向的都是同一个实例,改变其属性值,会影响到所有实例
2. 单例模式的优势: 因为只创了一个实例,这样大大节省了空间
3. 单例模式的应用场景:
	3.1 多次点击同一个弹窗
	3.2 下载多份材料的时候

需要注意的是: 单例模式确实节省了很多空间,但是也意味着你将多种不同的情况耦合在了一起,这样增大程序出错的机会,也不方便维护,更难测试

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值