《Javascript设计模式与开发实践》- 单例模式

360 阅读2分钟

单例模式

单例模式,顾名思义,只有一个实例。那么问题来了,什么只有一个实例。在 js 里面,能够创建实例的有构造函数和类(es6 新增,本质上是语法糖)。

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

在前端开发中,对于一些全局对象往往只需要一个,比如 window 对象。还有一些组件也不需要重复创建,比如 loading 组件。

实现单例模式

知道了单例模式是什么,实现一个单例模式也就并不困难。使用一个变量缓存实例就可以,每次创建实例判断是否已经创建过实例,如果是,返回缓存实例,

var Singleton = function(name) {
    this.name = name;
    this.instance = null;
};

Singleton.prototype.getName = function() {
    return this.name;
};

Singleton.getInstance = function(name) {
    if (!this.instance) {
        this.instance = new Singleton(name);
    }
    return this.instance;
};

var a = Singleton.getInstance('instance1');
var b = Singleton.getInstance('instance2');

console.log(a === b); // true

还可以使用 IIFE 实现,将实例缓存在闭包里面:

var Singleton = function(name) {
    this.name = name;
};

Singleton.prototype.getName = function() {
    return this.name;
};

Singleton.getInstance = function() {
    var instance = null;
    return function(name) {
        if (!instance) {
            instance = new Singleton(name);
        }
        return instance;
    };
};

var a = Singleton.getInstance('instance1');
var b = Singleton.getInstance('instance2');

console.log(a === b); // true

现在可以通过 Singleton.getInstance 来获取 Singleton 类的唯一实例。这种方式比较简单。与以往 new 的语法不符,需要使用者必须知道这是一个单例类。

创建一个透明的单例类:

var Singleton = (function() {
    var instance = null;
    var Singleton = function(name) {
        if (instance) {
            return instance;
        }
        this.name = name;
        return (instance = this);
    };
    return Singleton;
})();

用闭包和立即执行函数实现了一个用 new 来获取唯一实例的单例类。

但是有一个问题,这个类实际上做了两件事,创建对象和保证单例,当我们想要修改其中一个行为的时候就必须修改这个对象,这个时候我们可以引入代理类。

引入代理类

代理类保证单例,创建对象由专门对象负责。

var Singleton = function(name) {
    this.name = name;
};

var ProxySingleton = (function() {
    var instance = null;
    return function(name) {
        if (!instance) {
            instance = new Singleton(name);
        }
        return instance;
    };
})();
var a = new ProxySingleton('instance1');
var b = new ProxySingleton('instance2');

console.log(a === b); // true

惰性单例

惰性单例是指在需要的时候才创建对象实例。事实上我们开头写的实现就是一个惰性单例实例。instance 实例对象总是在调用 Singleton.getInstance 后创建。

小结

由示例可以看出,单例模式的实现离不开闭包和高阶函数,并且单例模式最好将保证单例和创建对象分开,这样才能具有单例模式的威力。

PS

这是我的读书笔记,如有错漏之处,欢迎各位大佬指出。