一、定义
保证一个类仅有一个实例,并提供一个访问它的全局访问点
二、核心
确保只有一个实例,并提供全局访问
实例实现
1. ES6实现单例
class Singleton {
constructor(name) {
this.name = name
}
static getInstance(name) {
if (!Singleton.instance) {
Singleton.instance = new Singleton(name)
}
return Singleton.instance
}
}
Singleton.prototype.getName = function() {
console.log(this.name)
return this.name
}
const s1 = new Singleton('张三');
const s2 = Singleton.getInstance('李四');
const s3 = Singleton.getInstance('王五');
s1.getName() // ==> 张三
s2.getName() // ==> 李四
s3.getName() // ==> 李四
从上面的结果可以看出,通过静态的getInstance可以实现单例模式,然后仍然可以通过new的方式获得多个实例。所以需要对构造函数constructor进行改些:
constructor(name) {
// 每次new的时候判断是否存在实例,若存在则直接返回该实例
if (!Singleton.instance) {
this.name = name
Singleton.instance = this;
}
return Singleton.instance
// return Signleton.getInstance() // 不能直接使用getInstance,否则会无限嵌套
}
再看结果:
const s1 = new Singleton('张三');
const s2 = Singleton.getInstance('李四');
const s3 = Singleton.getInstance('王五');
const s4 = new Singleton('赵六');
s1.getName() // ==> 张三
s2.getName() // ==> 张三
s3.getName() // ==> 张三
s4.getName() // ==> 张三
从结果说明,无论从new()方法,还是getInstance()方法,均只有一个示例。
2. ES5实现单例
function Person (name) {
// this.name = name // 仍然存在ES6中new时多个实例的问题
if (!Person.instance) {
this.name = name
Person.instance = this;
}
return Person.instance
}
Person.prototype.getName = function() {
console.log(this.name)}
Person.getInstance = (() => {
let instance = null;
return function (name) {
if(!instance) {
instance = new Person(name)
}
return instance
}
})()
const p0 = new Person('王五')
const p1 = Person.getInstance('张三');
const p2 = Person.getInstance('李四');
p0.getName() // ==> 王五
p1.getName() // ==> 王五
p2.getName() // ==> 王五
还可以抽离出通用的单例方法:
function getSingleton (fn) {
let instance = null;
return function () {
if (!instance) {
instance = fn.apply(this, arguments);
}
return instance
}
}
使用方法:
const PersonSingleton = getSingleton(function (name) {
const mgs = new Person(name);
return mgs;
})
PersonSingleton('张三').getName() // => 张三
PersonSingleton('李四').getName() // => 张三
跳转:设计模式目录