zoukankan      html  css  js  c++  java
  • JavaScript设计模式 单例模式

    单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

    先看一下,在Js中使用传统面向对象的单例模式。

    面向对象的单例模式,是通过new关键字来实例化我们想要的对象,并将其赋值给instance。

    通过使用变量instance来判断是否已经实例化,这里将创建一个div和保证只有一个对象的两个功能分割开来实现,对于代码的可维护性提高了很多。假设我们有一天,需要创建多个div,直接利用创建div的类就可以了,而不需要额外的修改。

    代理类是属于代理模式中的应用,会在代理模式中详细学习。

    var CreateDiv = function(html){
            this.html = html;
            this.init();
        };
        CreateDiv.prototype.init = function(){
            var div = document.createElement('div');
            div.innerHTML = this.html;
            document.body.appendChild(div);
        };
        //引入代理类proxySingletonCreateDiv
        var proxySingletonCreateDiv = (function(){
            var instance;
            return function(html){
                if(!instance)  instance = new CreateDiv(html)
                return instance;
            }
        })();
    
        //测试
        var a = new proxySingletonCreateDiv('svent1');
        var b = new proxySingletonCreateDiv('svent2');
        console.log(a === b);  //true

    我们知道单例模式的核心是确保只有一个实例,并提供全局访问。在JS的世界中,是不存在实质的可使用的类的,上面的只是模仿面向对象语言的实现方法,但Js有全局变量的特性,虽然它不是单例模式,但通常可以把全局变量当作单例模式来使用,如上面的例子可以修改为如下:

    将instance作为全局变量同时也作为唯一的创建的div。

    var CreateDiv = function(html){
            this.html = html;
            this.init();
        };
        CreateDiv.prototype.init = function(){
            var div = document.createElement('div');
            div.innerHTML = this.html;
            document.body.appendChild(div);
        };
        var instance = new CreateDiv('svent1');
    
        //测试
        var a = instance;
        var b = instance;
        console.log(a === b);  //true

     

    惰性单例

    惰性单例指的是在需要的时候才创建对象实例。

    在实际开发中,惰性单例的技术非常有用,正如当我们在web.qq.com即网页版QQ中,点击左边的导航里的QQ头像时,会弹出一个登录框,很明显这个登录框是唯一的,不可能同时出现,并且我们可以在用户点击的时候才来生成该登录框,这样当用户仅仅是浏览页面而不需要登陆时,可以节省一些DOM节点。

    在上面的面向对象开发单例模式的例子中,采用的就是懒惰单例,当用户第一次new代理类时,才开始实例化CreateDiv类。

    首先来写一个登录框例子:

    //创建登录框和判断单例
        var createLoginLayer = (function(){
            var div;
            return function(){
                if(!div){
                    div  = document.createElement('div');
                    ...
                    ...
                };
                return div;
            }
        })();
        //点击事件
        document.getElementById('loginBtn').onclick = function(){
            var loginLayer = createLoginLayer();
            ...
        }

    上面这个例子实际上还是有问题的,它把创建对象和管理单例的逻辑都放在一起,如果我们下次需要创建页面中唯一的iframe或其他标签,那么就得把上面的代码照抄一遍。

    //创建登录框和判断单例
        var createIframe = (function(){
            var iframe;
            return function(){
                if(!iframe){
                    iframe  = document.createElement('iframe');
                    ...
                    ...
                };
                return iframe;
            }
        })();
        //点击事件
        document.getElementById('loginBtn').onclick = function(){
            var loginLayer = createIframe();
            ...
        }

    根据设计模式的单一职责原则,我们需要把不变的部分隔离出来,如管理单例完成可以抽象出来,用一个变量来标志是否创建过对象,如果是,则在下次直接返回该对象。

    因为result变量在闭包中,所以永远不会被销毁。

    var getSingle = function(fn){
            var result;
            return function(){
                return result || (result = fn.apply(this,arguments));
            }
        }

    最后的实际代码:

    在这个实验中,我们把创建对象的职责和管理单例的职责分别放在两个方法里,这两个方法可以独立变化而互不影响,而当他们链接在一起,就完成了创建唯一实例对象的功能。

    var getSingle = function(fn){
            var result;
            return function(){
                return result || (result = fn.apply(this,arguments));
            }
        };
        var createDiv = function(){
            div  = document.createElement('div');
            ...
            ...
            return div;
        }
        var createLoginLayer = getSingle(createDiv);
    
        //点击事件
        document.getElementById('loginBtn').onclick = function(){
            var loginLayer = createLoginLayer();
            ...
        }
  • 相关阅读:
    python 基于os模块的常用操作
    python 文件的读写
    Spring Boot 2.0(五):Docker Compose + Spring Boot + Nginx + Mysql 实践
    Docker(四):Docker 三剑客之 Docker Compose
    Docker(三):Dockerfile 命令详解
    Docker(二):Dockerfile 使用介绍
    Docker(一):Docker入门教程
    虚拟机vmware centos7 扩展磁盘空间
    那些年我们遇到的坑(1)-Description Resource Path Location Type Archive for required library
    RPM安装命令总结
  • 原文地址:https://www.cnblogs.com/Darlietoothpaste/p/6675310.html
Copyright © 2011-2022 走看看