单例模式

保证一个类只有一个实例,并可以进行全局访问。例如,唯一的登陆Modal等,都适用单例模式实现。

基本实现

使用getInstance 来创建类,并缓存实例

1
2
3
4
5
6
7
8
9
10
11
12
13
class Singleton {
constructor (name){
this.name = name
}
}
Singleton.getInstance = (function (){
let instance = null
return name => {
return instance || (instance = new Singleton(name))
}
})()

缺点

  • 不透明,我们需要知道该实例有getInstance方法,否则不会这样创建实例
  • 不通用,总要重写getInstance方法

透明单例

使用闭包缓存实例,在构造函数中判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const Singleton = (function (){
let instance = null
return class BaseSingle {
constructor(name){
this.name = name
return instance || (instance = this)
}
}
})()
var b = new Singleton('wwe')
var c = new Singleton('wwx’)
b === c // true

缺点

  • 对远构造函数进行修改,且构造函数不符合单一功能原则,做了多件事
  • 闭包看起来很难受

代理实现

使用新的函数代理实现

1
2
3
4
5
6
7
const proxySingle = (function (){
ler instance
return function(){
return instance || (instance = new Singleton())
}
})()

decorator实现

这种东西,是不是可以用decorator来实现一下?

1
2
3
4
5
6
7
8
9
10
/**
* 单例模式,实例仅能被创建一次
* @param {class} Target 目标class
*/
export default Target => {
let instance
return function (...args) {
return instance || (instance = new Target(...args))
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@single
class Test {
constructor (name) {
this.name = name
}
show () {
console.log(this.name)
}
}
const a = new Test('hello')
const b = new Test('222')
console.log(a === b)

惰性单利

惰性浮窗,只有在点击时,才创建浮窗
避免全局的浮窗,但是确保访问的都是同一浮窗。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function single (fn) {
let result
return function(…args) {
result || (result = fn.apply(this, args))
}
}
$(‘button’).on(‘click’, function(){
// 创建实例
var div = single(function() {
var div = document.createElement(‘div’)
div.innerHTML = ‘弹框’
document.body.appendChild(div)
return div
})
// 管理实例
div.style.display = ‘block’
})

decorator:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 惰性单例
*/
export const getSingle = (target, name, descriptor) => {
let result,
fn = descriptor.value
descriptor.value = function (...args) {
return result || (result = fn.apply(this, args))
}
return descriptor
}

其他语言实现

实现原理

所有类都有构造方法,若显示定义构造方法,默认的构造方法就会失效。

所以说,将构造方法设置为private,外部程序就不能通过new来实例化了。

然后我们通过public的getInstance方法来维护实例被创建的次数并返回实例。

总结

单例模式非常常用,原理也很简单。总的来说,单例模式就是我们在创建对象时,希望该对象只可以被实例化一次,并且维护其只能进行一次实例化的工作不应该由用户进行,需要通过其本身或者代理方式进行。
以后在进行代码书写的时候,应该更多的考虑下,少写“bad smell”的代码