单例模式

2020/4/25 8:22:45

本文主要是介绍单例模式,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

设计模式

通俗讲,设计模式只是大量有经验的开发者在面对相同问题时,无数次使用过的解决方案。
可能很多人认为设计模式并没有多大用途,毕竟用普通的方法就能解决的问题,何必把代码逻辑搞得如此复杂,但从代码的可复用性和可维护性来看,好的设计的确可以节省大量的开发成本。优秀的 JavaScript 框架都运用了大量设计模式。

单例模式

单例模式的核心是确保只有一个实例对象,并提供全局访问。

使用场景

1、利用闭包封装需要频繁创建的对象

试想一下这样的场景,页面有一个登录窗,这个登录窗是唯一的,那么这个登录窗就非常适合用单例模式来创建。
我们可能会选择将这个登录窗定义在全局环境中:

例子:

<button id="login">登录</button>

<script>
    var loginBox = (function() {
        var div = document.createElement("div");
        div.innerHTML = "登录窗";
        div.style.backgroundColor = "bisque";
        div.style.display = "none";
        document.body.appendChild(div);
        return div;
    })();

    document.getElementById("login").onclick = function() {
        loginBox.style.display = "block";
    };
</script>

例子中,我们将登录窗缓存在全局环境中并隐藏起来,当用户点击时,才开始展示。这种单例模式称为饿汉式单例,即实例在页面加载完成时就被创建。
登录窗定义在全局存在很多问题,容易造成命名空间污染,所以有必要减少全局变量的使用。最为理想的方式是将实例封装在闭包中,只暴漏外部访问的接口。
另外,我们打开页面,可能根本不会点击登录按钮,那么加载的数据只是白白浪费内存而已,因此,与饿汉式单例相反的、实际工作中使用更多的是懒汉式单例,即实例在第一次引用时才被创建,然后将结果缓存在闭包中。

例子:

<button id="login">登录</button>

<script>
    var createLoginBox = (function() {
        var div;
        return function() {
            if (!div) {
                div = document.createElement("div");
                div.innerHTML = "登录窗";
                div.style.backgroundColor = "bisque";
                document.body.appendChild(div);
            }
            return div;
        }
    })();

    document.getElementById("login").onclick = function() {
        createLoginBox();
    };
</script>

通用懒汉式单例

页面中,往往不止一种弹出窗,如果下次我们需要创建确认框,就去复制现有的单例方法,这明显不是明智的做法。
理想的做法是将单例方法中变化的部分抽离出来,然后再以回调函数的形式传回给单例。本例中,创建弹窗的代码是变化的,而管理单例的代码是不变的,因此我们将创建弹窗的代码单独放置在一个方法里,这样一来,原来的单例方法中,只剩下可以通用的代码。

例子:

<button id="login">登录</button>
<button id="confirm">确认</button>

<script>
    //管理单例的逻辑始终是一样的
    var createSing = function() {
        var result;
        return function(fn) {
            if (!result) {
                result = fn();
            }
            return result;
        }
    };

    //创建登录窗的方法
    var createLoginBox = function() {
        var div = document.createElement("div");
        div.innerHTML = "登录窗";
        div.style.backgroundColor = "#ffe4c4";
        document.body.appendChild(div);
        return div;
    };

    //创建确认窗的方法
    var createConfirmBox = function() {
        var div = document.createElement("div");
        div.innerHTML = "确认窗";
        div.style.backgroundColor = "#ff5722";
        document.body.appendChild(div);
        return div;
    };

    //为登录窗创建一个实例
    var login = createSing();
    document.getElementById("login").onclick = function() {
        login(createLoginBox);
    };

    //为确认窗创建一个实例
    var confirm = createSing();
    document.getElementById("confirm").onclick = function() {
        confirm(createConfirmBox);
    };
</script>

2、通过对象字面量减少全局变量的数量

在 JavaScript 中,全局变量会造成命名空间的污染,因此项目中都会加以限制。如果想要全局环境中只存在一个对象,并能够提供全局访问,单例模式是最佳选择。

例子:

<button>绑定事件</button>

<script>
    //利用单例模式封装工具类(跨浏览器绑定事件)
    var EventUtil = {
        addHandler: function(element, type, handler) {
            if (element.addEventListener) {
                element.addEventListener(type, handler, false);
            } else if (element.attachEvent) {
                element.attachEvent('on' + type, handler);
            } else {
                element['on' + type] = handler;
            }
        },
        removeHandler: function(element, type, handler) {
            if (element.removeEventListener) {
                element.removeEventListener(type, handler, false);
            } else if (element.detachEvent) {
                element.detachEvent('on' + type, handler);
            } else {
                element['on' + type] = null;
            }
        }
    };

    //调用工具类
    var btn = document.getElementsByTagName("button")[0];
    EventUtil.addHandler(btn, "click", function() {
        alert("成功")
    });
</script>

*很多 JavaScript 插件、类库以及框架都会使用单例模式规范代码的各个功能模块。


如有错误,欢迎指正,本人不胜感激。



这篇关于单例模式的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程