定义
保证一个类仅有以一个实例,仅能被实例化/创建一次,并提供全局的访问点。
单例模式是一种重要的设计模式,有些对象我们只需要创建一个,比如浏览器的window对象,模态对话框。实现这种设计模式其实很简单,最重要的是在创建实例的时候,用一个标记变量判断实例是否已经创建。
普通青年写法
function Singleton(name){
this.name = name;
this.instance = null;
}
Singleton.prototype.getName = function(){
console.log('name: ' + this.name);
return this.name;
}
Singleton.getInstance = function(name){
if(!this.instance){
this.instance = new Singleton(name);
}
return this.instance;
}
var a = Singleton.getInstance('a');
var b = Singleton.getInstance('b');
alert(a === b);
点评:
该写法不透明,使用者必须知道用Singleton.getInstance
获取单例,而非通过更加通用的方法new xxx
方式。
老司机写法
var CreateDiv = function(html){
this.html = html;
this.init();
}
CreateDiv.prototype.init = function(){
var div = document.createElement('div');
div.innerHTML = this.html;
document.body.appendChild(div);
}
var SingletonDiv = (function(){
var instance;
return function(html){
if(!instance){
instance = new CreateDiv(html);
}
return instance;
}
})()
var a = SingletonDiv('yyh');
var b = SingletonDiv('yyh1');
点评:
使用代理类+普通的类,使得职责分明。普通类负责实现基本功能,代理类管理单例。CreateDiv可以直接生产一个实例,而加上代理,可以实现单例。有木有一种模块拼凑的快感,这就实现了低耦合。
华丽丽的ES6
在ES6中,可以使用static方法代替闭包存储单例。
静态方法的单例模式
class Singleton {
constructor(name) {
this.name = name;
}
static getInstance(name) {
if(!Singleton.instance) {
Singleton.instance = new Singleton(name)
}
return Singleton.instance;
}
getName() {
return this.name;
}
}
const singletonA = Singleton.getInstance('yyh1');
const singletonB = Singleton.getInstance('yyh2');
console.log(singletonA === singletonB);
console.log(singletonA.getName() === singletonB.getName());
点评:ES6的静态方法,和闭包一样能在减少全局变量污染的同时,使标记变量更加长久的保存在内存中不被回收。
老司机的新技能(更加通用的实现方式)
// 负责创建DIV的基本功能
class CreateDiv {
constructor(html) {
this.html = html;
this.init();
}
init() {
const div = document.createElement('div');
div.innerHTML = this.html;
document.body.appendChild(div);
}
}
// 负责管理单例
class ProxysingletonCreateDiv {
constructor(htmlStr) {
return ProxysingletonCreateDiv.getInstance(htmlStr);
}
static getInstance(name) {
if(!ProxysingletonCreateDiv.instance) {
ProxysingletonCreateDiv.instance = new CreateDiv(name)
}
return ProxysingletonCreateDiv.instance;
}
}
const singletonC = new ProxysingletonCreateDiv('yyh1');
const singletonD = new ProxysingletonCreateDiv('yyh2');
console.log(singletonC === singletonD);
singletonC.init();
singletonD.init();