【 js设计模式 】- 单例模式

125 阅读3分钟

beijing.png

设计模式是什么

在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案,简单来说是一套被反复使用、多数人知晓、经过分类编排的代码设计经验的总结,再通俗一点的说,设计模式就是给面向对象开发中一些好的代码设计起一个名字。

为什么要学习设计模式

使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性和可维护性。

下面是设计模式中单例模式的具体实现。

快上车.jpeg

单例模式的定义

一个类只会生成一个实例,且提供一个当前实例的全局访问点。单例模式是一种常用的设计模式,有一些对象我们通常只需要一个,例如vue中的new Vue(),浏览器中的window对象等。

实现单例模式

实现一个单例模式并不复杂,主要就是采用一个变量控制当前是否已经有生成该类的对象,若已经有对象了,则下一次实例化该类时直接返回已经生成的对象。

function Singleton(name) {
    this.name = name;
}
Singleton.getSingleton = (function () {
    let instance = null;
    return function (name) {
      if (!instance) {
        instance = new Singleton(name);
      }
      return instance;
    };
})();

let x = Singleton.getSingleton("x");
let y = Singleton.getSingleton("y");

console.log(x === y); // true

当前已经完成了一个简单的单例模式代码编写,但是你会发现还有一个问题在其中,使用者使用该类时需要明确知道当前的类是一个单例类,且要使用 Singleton.getSingleton() 方法来获取实例对象,这对于使用者来说十分不方便。

透明的单例模式

现在我们的目标是实现一个"透明"的单例类,即用 new 方法来创建单例对象,和实现普通对象创建的方法一样。

const Singleton = (function (name) {
    let instance = null;
    return function (name) {
      if (instance) {
        return instance;
      }
      this.name = name;
      return (instance = this);
    };
})();

let x = new Singleton("x");
let y = new Singleton("y");

console.log(x === y); // true

现在完成了透明单例类的编写,但它同样有一些缺点,在 Singleton 中的真正的构造函数中实际上进行了两件事的执行,第一个是判断当前是否有实例已经创建,第二个是进行实例的初始化,这违反了单一职责原则。什么时候当我们需要利用这个类创建许许多多个实例时,就需要对 Singleton 的构造函数进行改写,这是一件很麻烦的事,可以通过改写,将控制单一实例的逻辑从类中提取出来。

使用代理实现单例模式

通过引用代理类的方式解决上面存在的问题。

  function Singleton(name) {
    this.name = name;
  }
  const ProxySingleton = (function () {
    let instance = null;
    return function (name) {
      if (!instance) {
        instance = new Singleton(name);
      }
      return instance;
    };
  })();

  let x = new ProxySingleton("x");
  let y = new ProxySingleton("y");

  console.log(x === y); // true

通过代理类 ProxySingleton 我们一样能创建单例实例,不同的是,我们还可以通过 new Singleton 创建多个实例。

总结

单例模式是一种简单实用的设计模式,将对象实例化和单例控制两个功能分开于两个不同的函数中,将两个函数组合起来才能真正的体现单例模式的功能。