设计模式之单例模式

目录

定义

适用场景

非单例模式

单例模式实现

闭包方式实现

静态方法实现

场景举例


定义

单例模式是一种创建型设计模式,它保证一个类仅有一个实例,并提供一个访问它的全局访问点。

适用场景

"单例模式的特点,意图解决:维护一个全局实例对象。"

  • 引用第三方库(多次引用只会使用一个库引用,如 jQuery)
  • 弹窗(登录框,信息提升框)
  • 购物车 (一个用户只有一个购物车)
  • 全局态管理 store (Vuex / Redux)

项目中引入第三方库时,重复多次加载库文件时,全局只会实例化一个库对象,如 jQuerylodashmoment ..., 其实它们的实现理念也是单例模式应用的一种:

javascript 复制代码
// 引入代码库 libs(库别名)
if (window.libs != null) {
  // 直接返回
  return window.libs;    
} else {
  // 初始化
  window.libs = '...';   
}

非单例模式

在实现单例模式前,先看一下正常对象实例化,是否符合单例模式,用构造函数或者 Class(本质上还是构造函数)来实现都可以,我们这里就直接使用构造函数做示例,实现如下代码,可以看出相同的构造函数 Singleton,经过两次创建的对象实例 s1、s2 并不相等,对象指向的内存地址不一致,不是同一个实例,不符合单例模式。

javascript 复制代码
function Singleton() {}
const s1 = new Singleton();
const s2 = new Singleton();
console.log(s1); 
console.log(s2);
console.log(s1 === s2);
// {}
// {}
// false

单例模式实现

既然直接实例化不符合单例模式,那要怎么才能实现单例模式呢?要实现单例模式,需要构造函数具备判断自己是否已经创建过一个实例的能力。

闭包方式实现

不管执行多少次,返回的都是同一个实例,而闭包刚好就能满足我们的需求,创建一个立即执行函数,返回一个函数,而这个函数返回函数的内部变量 instance,也就是我们想要的唯一实例。我们实现了如下代码,进行了两次实例化,生成实例对象 s1、s2,根据输出可以判定 s1 与 s2 相等,即 s1,s2 指向同一块内存地址,是同一个实例,符合单例模式。

javascript 复制代码
const Singleton = (function () {
    // 实例变量
    let instance = null;
    // 实例的构造函数
    function getInstance() {}
    return function () {
      // 判断是否已经 new 过1个实例
      if (!instance) {
        // 如果实例不存在,则先new一个实例
        instance = new getInstance();
      }
      // 未来不管执行多少次,都返回这个唯一实例
      return instance;
    };
})();
const s1 = Singleton();
const s2 = Singleton();
console.log(s1);
console.log(s2);
console.log(s1 === s2);
// getInstance {}
// getInstance {}
// true
静态方法实现

ES6 Class 的静态方法也能实现单例模式,原理是借助于静态属性和静态方法,Class 的本质是一个构造函数,存在 static 修饰符的属性称为静态属性,直接挂载在构造函数上,当前类未被销毁时,静态属性也不会被销毁,具有类似于闭包的缓存作用,可以用来存储实例,实现了如下代码,借助 Singleton.getInstance() 生成实例对象 s1、s2,根据输出可以判定 s1 与 s2 相等,即 s1,s2 指向同一块内存地址,是同一个实例。

javascript 复制代码
class Singleton{

  static instance;

  show() {
    console.log('我是一个单例对象')
  }
  static getInstance() {
    // 判断是否已经new过1个实例
    if (!Singleton.instance) {
      // 若这个唯一的实例不存在,那么先创建它
      Singleton.instance = new Singleton()
    }
    // 如果这个唯一的实例已经存在,则直接返回
    return Singleton.instance
  }
}
const s1 = Singleton.getInstance()
const s2 = Singleton.getInstance()
console.log(s1 === s2); 
// true

实际上,基于 ES6 使用模块导入导出,也可以看作单例模式:

javascript 复制代码
// 比如这是 SingletonExample.js
// 可以定义一些属性,方法等等,然后通过 export 导出,其他模块再分别导入

const array_state = [];

const methodTest = function() {
    console.log('这是测试方法')
}

export default {
    array_state, methodTest
}

场景举例

利用单例模式思想 来实现 登录框的 显示和隐藏

javascript 复制代码
class LoginForm {
    constructor(){
        this.state = 'hide'
    }
    
    show(){
        if(this.state === 'show'){
            console.log('已经显示');
            return
        }
        this.state = 'show';
        console.log('登录框已显示')
    }
    
    hide(){
        if(this.state === 'hide'){
            console.log('已经隐藏');
            return
        }
        this.state = 'hide';
        console.log('登录框已隐藏')
    }
}

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

测试:

javascript 复制代码
let login1 = LoginForm.getInstance();
login1.show(); //打印:登录框显示成功


let login2 = LoginForm.getInstance();
login2.hide(); //打印:登录框隐藏成功

console.log(login1 === login2)
相关推荐
易元1 分钟前
模式组合应用-组合模式
后端·设计模式
秋难降7 分钟前
从浅克隆到深克隆:原型模式如何解决对象创建的 “老大难”?😘
后端·设计模式·程序员
ssshooter4 小时前
上下文工程:为高级大型语言模型构建信息环境
人工智能·算法·设计模式
郝学胜-神的一滴7 小时前
C++组合模式:构建灵活的层次结构
开发语言·c++·程序人生·设计模式·组合模式
程序员水自流8 小时前
Java设计模式是什么?核心设计原则有哪些?
java·设计模式
用户413079810618 小时前
面向对象六大设计原则
设计模式
YoungUpUp8 小时前
【电子设计自动化(EDA)】Altium Designer25——电子设计自动化(EDA)软件版保姆级下载安装详细图文教程(附安装包)
运维·设计模式·fpga开发·自动化·eda·电路仿真·电子设计自动化
NorthCastle9 小时前
设计模式-行为型模式-命令模式
设计模式·命令模式
Aeside11 天前
漫谈代理模式,静态代理到 JDK 和 CGLIB 动态代理
java·设计模式
小凯 ོ1 天前
实战原型模式案例
java·后端·设计模式·原型模式