设计模式之单例模式

目录

定义

适用场景

非单例模式

单例模式实现

闭包方式实现

静态方法实现

场景举例


定义

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

适用场景

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

  • 引用第三方库(多次引用只会使用一个库引用,如 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)
相关推荐
Engineer邓祥浩2 小时前
设计模式学习(16) 23-14 命令模式
学习·设计模式·命令模式
Maddie_Mo3 小时前
智能体设计模式 第二章:路由模式
设计模式
一条闲鱼_mytube6 小时前
智能体设计模式(五)人机协同-知识检索RAG-智能体间通信
网络·人工智能·设计模式
小码过河.6 小时前
设计模式——建造者模式
单片机·设计模式·建造者模式
小码过河.8 小时前
设计模式——工厂方法模式
设计模式·工厂方法模式
把csdn当日记本的菜鸡9 小时前
Java设计模式简单入门
java·开发语言·设计模式
老蒋每日coding9 小时前
AI Agent 设计模式系列(十一)—— 目标设定和监控模式
人工智能·设计模式·langchain
蔺太微9 小时前
外观模式(Facade Pattern)
设计模式·外观模式
进击的小头9 小时前
C语言实现设计模式的核心基石
c语言·开发语言·设计模式
Engineer邓祥浩10 小时前
设计模式学习(15) 23-13 模版方法模式
java·学习·设计模式