浅谈设计模式中的-单例模式

91 阅读3分钟

「回顾2022,展望2023,我正在参与2022年终总结征文大赛活动

前言

单例模式相信大家都有所听闻,甚至也写过不少了。在面试中也是考得最多的其中一个设计模式,本文也是刚学了一点javascript的单例模式的体会,希望对大家能够有所帮助~~~

什么是单例模式

单例模式是指在内存中只会创建且仅创建一次对象的设计模式。 在程序中多次使用同一个对象且作用相同时,为了防止频繁地创建对象使得内存飙升,单例模式可以让程序仅在内存中创建一个对象,让所有需要调用的地方都共享这一单例对象。
在JavaScript中,通俗来讲就是 保证一个类,仅有一个实例

3.png

单例模式的类型

单例模式有两种类型:

  • 懒汉式:在真正需要使用对象时才去创建该单例类对象
  • 饿汉式:在类加载时已经创建好该单例对象,等待被程序使用

这里,我们主要针对于懒汉式类型展开来聊一聊吧~

模式特点

  • 类只有一个实例
  • 全局可访问
  • 推迟初始化(与静态类,对象的区别)
  • 主动实例化

应用场景

  • 登录弹窗
  • 购物车
  • 命名空间
  • 引入第三方库(多次引用只会使用一个库引用,如jQuery)
  • 全局态管理store-Vuex

懒汉式创建单例对象

核心方法大概就是:创建对象的方法是在程序使用对象前,先判断该对象是否已经实例化 (判空), 若已实例化直接返回该类对象。,否则就先执行实例化操作。

6.png

简单版单例模式

//    写法一
class Person {
    say() {
        console.log('百宝箱');
    }

    static getInstance() {
        if (!Person.instance) {
            Person.instance = new Person();
        }
        return Person.instance
    }
}

const p1 = Person.getInstance()
const p2 = Person.getInstance()
console.log(p1 === p2);  // 执行结果为 true

让这个类永远只能创建出一个实例对象,这个就是单例模式

//  闭包的写法
class Person {
    say() {
        console.log('百宝箱');
    }

}

Person.getInstance = (function () {
    let instance = null
    return function () {
        if (!instance) {
            instance = new Person()
        }
        return instance
    }
})()

const p1 = Person.getInstance()
const p2 = Person.getInstance()
console.log(p1 === p2);    // 执行结果为 true

以上就是懒汉式创建单例对象的方法。这里我们其实也可以联想到,vuex的使用也是单例模式,vuex的使用是为了实现全局的store,创建store的方式是把单例模式的思想得以应用。

“惰性”单例模式
需要时才创建实例对象,按需加载。

需求:页面弹窗提示。多次调用,都只有一个弹窗对象,内部html不同

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>单例模式的弹框</title>
    <style>
        #model {
            width: 200px;
            height: 200px;
            line-height: 200px;
            position: fixed;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            border: 1px solid #000;
            text-align: center;
        }
    </style>
</head>

<body>
    <button id="open">打开弹框</button>
    <button id="close">关闭弹框</button>

    <script>
        const Model = (function () {
            let model = null
            return function () {
                if (!model) {
                    model = document.createElement('div')
                    model.innerHTML = '全局唯一的model'
                    model.id = 'model'
                    model.style.display = 'none'
                    document.body.appendChild(model)
                }
                return model
            }
        })()

        document.getElementById('open').addEventListener('click', () => {
            const model = new Model();
            model.style.display = 'block';
        })
        document.getElementById('close').addEventListener('click', () => {
            const model = new Model();
            if (model) {
                model.style.display = 'none';
            }
        })
    </script>
</body>

</html>

优缺点

  • 优点:适用于单一对象,只生成一个对象实例,避免频繁创建和销毁实例,减少内存占用
  • 缺点:不适用动态扩展对象,或需创建多个相似对象的场景