【04】前端常用的设计模式之单例模式

61 阅读2分钟

单例模式

概念

  • 一个 对象/实例 只能被创建一次
  • 创建之后缓存起来,以后继续使用
  • 即,一个系统中只有一个

Typescript 静态属性

  • 普通属性是 实例属性/对象属性
  • static 静态属性
// src/demo04/static.ts
class Foo {
  // 实例/对象 属性
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  getName() {
    return this.name;
  }

  // 静态属性
  static flag = '二次元';
  static getFlag() {
    // this === Foo
    return this.flag;
  }
}

const f1 = new Foo('张三');
f1.name; // 张三
f1.getName(); // 张三

Foo.flag; // 二次元
Foo.getFlag();

export {};

UML 类图

单例模式

代码演示

// src/demo04/ts.ts
// 使用 ts 特性演示
class Singleton {
  // private - 外部无法初始化
  private constructor() {
    // ...
  }

  // static 属性
  private static instance: Singleton | null;

  // static 方法
  static getInstance(): Singleton {
    if (Singleton.instance == null) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }
}

// 创建实例
const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
console.log(s1 === s2); // true

// 报错 private
// const s3 = new Singleton();
// Singleton.instance

export {};
// src/demo04/js.js
function genGetInstance() {
  let instance; // 闭包
  class SingleTon {
    // ...
  }

  return () => {
    if (instance == null) {
      instance = new SingleTon();
    }
    return instance;
  };
}

const getInstance = genGetInstance();

const s1 = getInstance();
const s2 = getInstance();
console.log(s1 === s2); // true

// es6 commonjs 模块化 语法

// src/demo04/getInstance.js
let instance; // 闭包
class SingleTon {}

export default () => {
  if (instance == null) {
    instance = new SingleTon();
  }
  return instance;
};
// 注意:外部只能 import 函数导入

场景

JQuery 只有一个 $

if (window.JQuery != null) {
  return window.JQuery;
} else {
  // 初始化
}

模拟登录框

// src/demo04/login.js
class LoginForm {
  constructor() {
    this.state = 'hide';
  }
  show() {
    if (this.state === 'show') {
      console.log('已经显示');
    } else {
      this.state = 'show';
      console.log('登录框显示成功');
    }
  }
  hide() {
    if (this.state === 'hide') {
      console.log('已经隐藏');
    } else {
      this.state = 'hide';
      console.log('登录框隐藏成功');
    }
  }
}

LoginForm.getInstance = (function () {
  let instance;
  return function () {
    if (!instance) {
      instance = new LoginForm();
    }
    return instance;
  };
})();

// 测试
let login1 = LoginForm.getInstance();
login1.show();

let login2 = LoginForm.getInstance();
login2.hide();

console.log('login1 === login2:', login1 === login2);

其他

  • react redux、vuex
  • 购物车

设计原则验证

  • 内部封装 getInstance,高内聚、低耦合
  • 符合单一职责原则,只能实例化唯一的对象
  • 没法具体开放封闭原则,但是绝对不违反开放封闭原则

注意

  • JS 是单线程语言,如果是 Java 等多线程语言,单例模式需要加线程锁。
  • 静态方法中的 this
  • 前端用到严格的单例模式并不多,但单例模式的思想到处都有

项目地址