单例模式

150 阅读2分钟

一、介绍

定义:

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

主要解决:

一个全局使用的类频繁地创建与销毁。

如何解决:

判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

应用实例:

Vuex,Redux,ES6中的export等

使用场景:

  1. 仅需创建一次实例,在vue中的use方法中,如果已经安装一次插件之后,将不再安装。

优点:

  • 只创建一个实例,避免多次创建销毁导致的性能消耗和内存消耗。
  • 对于全局状态管理来说,避免多次创建导致数据混乱,不可追踪。

缺点:

二、代码实现

1.基本实现

利用ES6语法,通过new类创建一个实例。

把要返回的单例定义成类的静态属性

class BangBangTang {
  static instance = undefined
  constructor(type) {
    if (BangBangTang.instance) {
      return BangBangTang.instance
    } else {
      this.type = type
      BangBangTang.instance = this
    }
  }
}
const tang = new BangBangTang('超级棒棒糖')
const tang_ = new BangBangTang('棒棒糖')
console.log(tang)
console.log(BangBangTang.instance)

把要返回的单例隐藏在闭包里

const BangBangTang = (function () {
  let instance = undefined
  return class {
    constructor(data) {
      if (!instance) {
        this.name = data.name
        instance = this
      } else {
        return instance
      }
    }
  }
})()

const tang = new BangBangTang({ name: "超级棒棒糖" })
const tang_ = new BangBangTang({ name: "棒棒糖" })
console.log("tang:", tang, "tang_:", tang_,)
console.log(tang === tang_) //true

2.拓展:需要给多个类添加单例模式

遵守单一职责原则:把创建对象和保证只有一个对象两个功能分开

需求:需要给多个类添加单例模式,减少重复判断单例的代码

通过代理模式

class BangBangTang {
  constructor(data) {
    this.name = data.name;
  }
}

class Toy {
  constructor(data) {
    this.name = data.name;
  }
}
//代理模式
const proxySingletonCreate = function (fn) {
  let instance = undefined;
  return function (data) {
    if (!instance) {
      instance = new fn(data);
    }
    return instance;
  };
};

const SingletonToy = proxySingletonCreate(Toy);
const SingletonTang = proxySingletonCreate(BangBangTang);
const toy = new SingletonToy({ name: "小火车" });
const toy_ = new SingletonToy({ name: "小火车" });
console.log("toy:", toy, "toy_:", toy_);
console.log(toy === toy_); //true

const tang = new SingletonTang({ name: "超级棒棒糖" });
const tang_ = new SingletonTang({ name: "棒棒糖" });
console.log("tang:", tang, "tang_:", tang_);
console.log(tang === tang_); //true

三、惰性单例

概念:在需要的时候才创建对象实例

四、JavaScript中的单例模式

JavaScript是基于原型的面向对象,也是动态语言类型。可以直接创建一个对象,而不需要通过类来创建对象。

所以,可以省去创建类的代码,而直接生成对象。

const proxySingletonCreate = function () {
  let instance = undefined;
  return function (data) {
    if (!instance) {
      instance = data
    }
    return instance
  }
}
const getToy = proxySingletonCreate()
const toy = getToy({ name: "变形金钢" })
const toy_ = getToy({ name: "芭比娃娃" })
console.log(toy, toy_)
console.log(toy === toy_)

提供一个访问它的全局访问点。

可以采用全局对象,提供一个访问点。要处理好全局变量污染的问题。

参考资料:

单例模式 | 菜鸟教程 (runoob.com)

JavaScript设计模式与开发实践-曾探-微信读书 (qq.com)