js_单例设计模式

实现单例模式

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

单例模式的实现:主要通过创建一个标志变量来保存第一次创建过的实例,当下一次获取该类的实例时进行判断标志变量是否已经被赋值,如果已被赋值直接返回标志位上保存的值。

//第一种
var Singleton = function( name ){ 
 this.name = name; 
 this.instance = null; 
}; 
Singleton.prototype.getName = function(){ 
 alert ( this.name ); 
}; 
Singleton.getInstance = function( name ){ 
 if ( !this.instance ){ 
 this.instance = new Singleton( name ); 
 } 
 return this.instance; 
}; 
var a = Singleton.getInstance( 'sven1' ); 
var b = Singleton.getInstance( 'sven2' ); 
alert ( a === b ); // true


//第二种
var Singleton = function( name ){ 
 this.name = name; 
}; 
Singleton.prototype.getName = function(){ 
 alert ( this.name ); 
}; 
Singleton.getInstance = (function(){ 
 var instance = null; 
 return function( name ){ 
 if ( !instance ){ 
 instance = new Singleton( name ); 
 } 
 return instance; 
 } 
})();

透明的单例模式

我们现在的目标是实现一个“透明”的单例类,用户从这个类中创建对象的时候,可以像使用其他任何普通类一样。在下面的例子中,我们将使用 CreateDiv 单例类,它的作用是负责在页面中创建唯一的 div 节点

var CreateDiv = (function(){ 
 var instance; 
 var CreateDiv = function( html ){ 
 if ( instance ){ 
 return instance; 
 } 
 this.html = html; 
 this.init();
  return instance = this; 
 }; 
 CreateDiv.prototype.init = function(){ 
 var div = document.createElement( 'div' ); 
 div.innerHTML = this.html; 
 document.body.appendChild( div ); 
 }; 
 return CreateDiv; 
})(); 
var a = new CreateDiv( 'sven1' ); 
var b = new CreateDiv( 'sven2' ); 
alert ( a === b ); // true

问题:破坏了“单一职责原理”CreateDiv的构造函数实际上负责了两件事情。第一件事创建对象和初始化init方法,第二件是保证只有一个对象。

使用代理模式实现单例模式

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 ); 
}; 

接下来引入代理类 proxySingletonCreateDiv:
var ProxySingletonCreateDiv = (function(){ 
 var instance; 
 return function( html ){ 
 if ( !instance ){ 
 instance = new CreateDiv( html ); 
 } 
 return instance; 
 } 
})(); 

var a = new ProxySingletonCreateDiv( 'sven1' ); 
var b = new ProxySingletonCreateDiv( 'sven2' ); 
alert ( a === b );

解决了上面的 “单一职责原理”

通用的惰性单例

现在我们就把如何管理单例的逻辑从原来的代码中抽离出来,这些逻辑被封装在 getSingle函数内部,创建对象的方法 fn 被当成参数动态传入 getSingle 函数接下来将用于创建登录浮窗的方法用参数 fn 的形式传入 getSingle,我们不仅可以传入还能传createScript、createIframe、createXhr 等。之之后再让 getSingle 返回一个新的函数,并且用一个变量 result 来保存 fn 的计算结果。result 变量因为身在闭包中,它永远不会被销毁。在将来的请求中,如果 result 已经被赋值,那么它将返回这个值。

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

var createLoginLayer = function(){ 
 var div = document.createElement( 'div' ); 
 div.innerHTML = '我是登录浮窗'; 
 div.style.display = 'none'; 
 document.body.appendChild( div ); 
 return div; 
}; 

var createSingleLoginLayer = getSingle( createLoginLayer ); 
document.getElementById( 'loginBtn' ).onclick = function(){ 
 var loginLayer = createSingleLoginLayer(); 
 loginLayer.style.display = 'block'; 
}; 

下面我们再试试创建唯一的 iframe 用于动态加载第三方页面:
var createSingleIframe = getSingle( function(){ 
 var iframe = document.createElement ( 'iframe' ); 
 document.body.appendChild( iframe ); 
 return iframe; 
}); 

document.getElementById( 'loginBtn' ).onclick = function(){ 
 var loginLayer = createSingleIframe(); 
 loginLayer.src = 'http://baidu.com'; 
};

getSingle函数中,用到了闭包和高阶函数的概念。单例模式是一种既简单又实用的模式,特别是惰性单例技术,再适合的时候才创建对象,并且只创建一个。更有意思的是创建对象和和管理单例职责被分布在不同的方法中,当两个方法组合起来的时候才会具备单例模式的特性。

发布了7 篇原创文章 · 获赞 5 · 访问量 224

猜你喜欢

转载自blog.csdn.net/weixin_42362211/article/details/103203882