什么叫做单例模式?

[begin]单[/begin]例模式(Singleton Pattern),是一种简单常用的软件设计模式。在数学和逻辑学中,singleton被定义为只包含一个元素的集合。那在JavaScript中我们将其理解为只包含一个称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的一个类只有一个实例。即一个类只有一个对象实例

单例模式的要点有三个:

  1. 某个类只能有一个实例;
  2. 它必须自行创建这个实例;
  3. 它必须自行向整个系统提供这个实例。

单例模式的优点和缺点

优点

  • 实例控制性
  • 灵活性

实例控制性 是意味着单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。

在团队开发中,为了实现一些相似的功能,比如不同页面之间的表单验证,可能需求是不一样的,但是呢命名可能一样,这时就会产生冲突,这时候单例模式就能很好的解决这个问题。

灵活性在于该类控制了实例化过程,所以针对实例化过程能实现便捷修改。

缺点

  • 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。 
  • 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。 
  • 单例类的职责过重,在一定程度上违背了“单一职责原则。 
  • 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

代码示例

小王小李邻居例子

/*
 * @Author: Endcat 
 * @Date: 2019-02-21 19:09:46 
 * @Last Modified by: Endcat
 * @Last Modified time: 2019-02-21 20:41:55
 */
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <!-- 假想背景:
    1、两个独立的对象,xiaoWang和xiaoLi,即小王和小李。
    2、让xiaoLi跟xiaoWang通过门铃menLing进行通信
    3、首先判断小王家xiaoWangjia有没有门men,如果有通过门铃通信didi,如果没有就造一个门。
    4、对象之间开始相互通信。 -->
    <script>
        var xiaoWang = (function (argument){
            var xiaoWangjia = function(message){
                this.menLing = message;
            }
            var men;
            var info = {
                sendMessage:function(message){
                    if (!men){
                        men = new xiaoWangjia(message);
                    };
                    return men;
                }
            };
            return info;
        })();
        
        var xiaoLi = {
            callXiaowang:function(msg){
                var _xiaoWang = xiaoWang.sendMessage(msg);
                alert(_xiaoWang.menLing);
                _xiaoWang = null; //垃圾回收内存释放
            }
        };
        
        xiaoLi.callXiaowang('didi');
    </script>
</body>
</html>

应用开发举例

/*
 * @Author: Endcat 
 * @Date: 2019-02-21 20:53:55 
 * @Last Modified by:   Endcat 
 * @Last Modified time: 2019-02-21 20:53:55 
 */
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script>
        // 页面上有若干个按钮
        // 如果用下面的结构,控制同一个变量,势必会很麻烦
        $('#a').click(function(){
            //逻辑特别多
            var varA = 4;
        });
        $('#b').click(function(){
            //逻辑特别多
        });
        $('#c').click(function(){
            //逻辑特别多
        });
        $('#d').click(function(){
            //逻辑特别多
        });
        $('#e').click(function(){
            //逻辑特别多
        });
        </script>
</body>
</html>
/*
 * @Author: Endcat 
 * @Date: 2019-02-21 20:53:55 
 * @Last Modified by: Endcat
 * @Last Modified time: 2019-02-21 21:05:54
 */
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script>
        // 页面上有若干个按钮
        // 如果用下面的结构,控制同一个变量,势必会很麻烦
        // 我们可以通过封装对象来实现上述要求,同时具有可维护性。
        var top = {
            init:function(){
                this.render();
                this.bind();
            },
            a:4,
            render:function(){
                var me = this;
                me.btna = $('#a');
            },
            bind:function(){
                var me = this;
                me.btna.click(function(){
                    // 取出业务逻辑
                    me.test();
                });
            },
            test:function(){
                a = 5;
            }
        }
        var banner = {
            init:function(){
                this.render();
                this.bind();
            },
            a:4,
            render:function(){
                var me = this;
                me.btna = $('#d');
            },
            bind:function(){
                var me = this;
                me.btna.click(function(){
                    // 取出业务逻辑
                    me.test();
                });
            },
            test:function(){
                a = 6;
                // top.a = 6;
            }
        }

        top.init();
        banner.init();
        
        // $('#a').click(function(){
        //     //逻辑特别多
        //     var varA = 4;
        // });
        // $('#b').click(function(){
        //     //逻辑特别多
        // });
        // $('#c').click(function(){
        //     //逻辑特别多
        // });
        // $('#d').click(function(){
        //     //逻辑特别多
        // });
        // $('#e').click(function(){
        //     //逻辑特别多
        // });
        </script>
</body>
</html>

[toc]

代码文件


Melancholy.