单例模式定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式场景:有一些对象往往只需要有一个,比如线程池、全局缓存浏览器中的Windows对象等
1、实现单例模式
要实现一个标准的单例模式并不复杂,无非是用一个变量来标志当前是否已经为某个类创建过对象,如果是则在下一次获取该类的实例时,直接返回之前创建的对象
image.png
或者:

     var Singleton = function(name) {
        this.name = name;
    }
    Singleton.prototype.getName = function() {
        console.log(this.name)
    }
    Singleton.getInstance = (function(name) {
        var instance = null
        return function(name) {
            if(!instance) {
                instance = new Singleton(name)
            }
            return instance
        }
    })()
    var a = Singleton.getInstance('aa')
    var b = Singleton.getInstance('bb')
    console.log(a === b) // true

但是这种方法增加了类的“不透明性”,Singleton必须知道这是一个单例类,且getInstance方法是不透明的,使用必须知道又该方法,当我们打印console.log(new Singleton('cc')),结果如下:
image.png

2、透明的单例模式
目的:创建该类时候,可以像使用其他普通类一样;
例子:我们将创建一个CreateDiv单例类,它的作用是在页面中创建唯一的div节点
image.png
image.png
这里可以看到当我们console.log(b)时,构造函数html的值还是'marin',到这里我要明确一点 单例模式定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
但是它还是有一些缺点。未了把判断的标志变量instance封装起来,我们使用了匿名函数(自运行)和闭包,并让让这个匿名函数返回真正的Singleton构造方法,这让阅读起来很难理解,同时增加了程序的复杂程度
var CreateDiv = function(html) {

if(instance) {
    return instance
}
this.html = html;
this.init();
return instance = this

}
这段代码中 CreateDiv的构造函数实际负责两件事,1、创建实例对象(instance=this)并保证只用一个实例if(instance)。2、执行初始化init()。这里还有个缺点(函数的单一职责原则)
假如我们某一天需要用这个类,在页面创建多个div,即要让这个类从单例类变成一个普通的可以生产多个实例的类,那我们就必须改写CreateDiv构造函数,把控制创建唯一的标志变量 var instance去掉,这种修改会带来不必要的烦恼。

3、用代理来实现单例模式
image.png
这样一来就将 CreateDiv变成一普通类,仅仅去创建div,
实现单例模式让ProxySingleton 去实现
单例模式的核心是确保只有一个实例,并提供全局访问


breathfish
43 声望2 粉丝