定义
单例模式(Singleton Pattern)属于创建型设计模式,是经典设计模式中最简单的一种,也是开发中最常见的一种。顾名思义,单例可以理解为一个类有且仅有一个实例对象,每次创建实例对象时,如果存在实例则返回该实例。
应用场景
不适合出现多个实例的场景,都可以作为单例模式的应用场景:
- window对象、JQuery对象、Vuex对象。
- 登录模块弹窗。
- 全局主题配置对象。
- 第三方密钥对象。
优缺点
优点
- 易维护:将维护对象目标放在一个目标上,便于管理和维护。
- 易访问:通常可以挂载在一些根节点,以极为方便的调用方式可以直接读取。
- 低消耗:仅维护一个对象,不会创建多个对象,资源消耗较少。
缺点
- 安全隐患:单例对象通常会使用全局对象或者一些上层节点进行存储,容易暴露内部细节。
- 巨石对象:若单例对象成员较多,存储在全局对象造成臃肿,难以排查形成巨石。
- 难以扩展:没有抽象类的单例对象,违背了单一职责原则,内部功能过多容易导致扩展性差等问题。
JavaScript实现
JavaScript并不是标准的基于类的面向对象编程语言,更偏向函数性编程方式。根据这个特性,结合ES6之后的class关键字,可以基本写出Human类。
我们创建了两个Human的实例h1和h2,分别用各自的实例对象调用talk方法,输出的分别是“Jimmy”和“Lucy”,说明我们创建了两个实例对象。
class Human { constructor(name) { this.name = name; } talk() { console.log(this.name); } } const h1 = new Human('Jimmy'); const h2 = new Human('Lucy'); h1.talk(); // Jimmy h2.talk(); // Lucy
实现单例通常需要一个中间方法,将Human类转化成单例类,每次new这个单例函数时,都要判断实例是否存在,如果存在则直接返回,否则重新创建。
编写getSingle方法进行调用,通过闭包的方式存储全局唯一的实例对象,无论以后new多少次,都会返回instance所在存储的实例对象。
// 中间方法 用来将构造函数转换为单例模式 function getSingle(fn) { let instance = null; return function(args) { if (instance === null) { // 如果instance为null则创建实例 instance = new fn(args); } return instance; } } class Human { constructor(name) { this.name = name; } talk() { console.log(this.name); } } const SingleHuman = getSingle(Human); const h3 = new SingleHuman('Jimmy'); const h4 = new SingleHuman('Lucy'); h3.talk(); // Jimmy h4.talk(); // Jimmy
TypeScript实现
TypeScript的写法更像是那种比较标准的基于类的写法,可以利用private的特性来控制构造函数的可访问性,使用静态属性去存储实例,再通过静态方法的调用方式去实现。
class Human { private static instance: Human; // 静态属性,用于存储全局唯一的实例 private name: string; // 私有构造方法 无法使用new调用 private constructor(name: string) { this.name = name; } public static getInstance(name: string): Human { if (Human.instance === null) { Human.instance = new Human(name); } return Human.instance; } } const h1 = Human.getInstance('Jimmy'); const h2 = Human.getInstance('Lucy'); console.log(h1 === h2); // true
总结
设计模式对于前端而言需要细细品味,多看一次多思考一次可能会有新的收获,无形中会改变你的编码思路,提高代码质量。前端必须掌握的设计模式系列持续更新,如果对您有帮助希望多多点赞哦!