什么是单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

推荐使用惰性单例的方式创建,即在需要时才创建单例对象。并且需要把不变的部分隔离出来,把管理单例的逻辑和创建对象的逻辑分开,这两个方法可以独立变化而不互相影响。当它们连接在一起时,就完成了创建唯一实例对象的功能。

面向对象例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//以下是基本实现方法,但是并没有实现:
//并且需要把不变的部分隔离出来,把管理单例的逻辑和创建对象的逻辑分开
//这两个方法可以独立变化而不互相影响。当它们连接在一起时,就完成了创建唯一实例对象的功能。"
//的功能。因为再加一个单例元素时,需要修改管理单利的类。SingletonDOM只是为CreateDOM而生的管理类。

export class SingletonDOM{
constructor() {
this.createDOM = new CreateDOM;
}

create() {
if (!this.instance) {
return this.instance = this.createDOM.create();
}
return this.instance;
}
}

export class CreateDOM{
create(type) {
return document.createElement(type || 'div');
}
}

export class CreateButton{
create() {
return document.createElement('button');
}
}

//通用管理单例的类。

export class GetSingleton{
constructor(ClassName) {
this.obj = new ClassName();
}

create() {
if (!this.instance) {
return this.instance = this.obj.create();
}
return this.instance;
}
}

函数式例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/**
* 使用单例模式实现一个登陆框。
* 包含一个智能命令模式,即可以直接实现请求的命令,不需要接收者的存在。
*/
(function () {

var createLoginDiv = function () {
var div;
div = document.createElement('div');
div.setAttribute('class', 'login');
document.querySelector('#app').appendChild(div);

var child = document.createElement('div');
child.setAttribute('class', 'login-child');
child.innerText = 'Login Dialog';
div.appendChild(child);
return div;
};

var createLoginButton = function () {
var button;
button = document.createElement('input');
button.type = 'button';
button.value = 'login';
button.setAttribute('class', 'loginBtn');

document.querySelector('#app').appendChild(button);
return button;
};

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

var createSingleLogin = getSingle(createLoginDiv);
var createSingleLoginButton = getSingle(createLoginButton);

var openLoginDivCommand = (function () {
var loginDiv = createSingleLogin();
return {
excute: function () {
loginDiv.addEventListener('click', function (e) {
if (e.target.getAttribute('class') !== 'login-child') {
macroCommand.undo();
}
});
loginDiv.style.display = 'flex';
},
undo: function () {
loginDiv.style.display = 'none';
}
}
})();

var clearInputCommand = (function () {
var input = document.querySelector('input');
var cache;
return {
excute: function () {
cache = input.value;
input.value = '';
},
undo: function () {
input.value = cache;
}
}
})();

var macroCommand = (function () {
var commandList = [];
return {
add: function (command) {
commandList.push(command);
},
excute: function () {
for (var i = 0, len = commandList.length; i < len; i++) {
commandList[i].excute();
}
},
undo: function () {
for (var i = 0, len = commandList.length; i < len; i++) {
commandList[i].undo();
}
},
redo: function () {
macroCommand.excute();
}
}
})();

macroCommand.add(openLoginDivCommand);
macroCommand.add(clearInputCommand);

var init = function () {
var loginButton = createSingleLoginButton();
loginButton.addEventListener('click', function () {
macroCommand.excute();
});

setTimeout(function () {
macroCommand.redo();
}, 10000);
};

init();

})();