Javascript设计模式与开发实践详见(一:单例模式)

设计模式(Design

pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

本文系列主要针对JavaScript语言特性全面总结了16个常用的设计模式,讲解了JavaScript面向对象和函数式编程方面的基础知识,介绍了面向对象的设计原则及其在设计模式的体现,本文将教会你如何把经典的设计模式应用到JavaScript语言中,编写出优美高效,结构化和可维护的代码。

单例模式 :


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

单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池,全局缓存,浏览器中的window对象等。在JavaScript开发中,单例模式的用途同样非常广泛。试想一下,当我们点击登录按钮的时候,在页面中会出现一个登录浮窗,而这个登录浮窗是唯一的,无论单击多少次登录按钮,这个浮窗只会被创建一次,那么这个登录浮窗就适合用单例模式来创建。

实现单例模式


要实现一个标准的单例模式并不复杂,无非是用一个变量来标志当前是否已经为某个类创建过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象。

参见代码:

  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('ritsu1');

var b = Singleton.getInstance('ritsu2');

alert(a === b)      //true

判断为true也就说明了之后所创建的任何实例其实都是第一个,可自行控制台测试:

ok,现在虽然已经完成了一个单例模式的编写,但这段单例模式代码的意义并不大。

代理实现单例模式


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

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 ProxySingletonCreateDiv = (function  () {

var instance;

return function  (html) {        // 这里使用了闭包的一些特性

if(!instance){

instance = new CreateDiv(html);

}

return instance;

}

})();

var a = new ProxySingletonCreateDiv('ritsu1');

var b = new ProxySingletonCreateDiv('ritsu2');

alert(a === b) //true

判断为true也就说明了之后所创建的任何实例其实都是第一个,可自行控制台测试:

前面提到的二种单例模式的实现,更多的是接近传统面向对象中的实现,单例对象由类而来,下面我们讲讲JavaScript的单例模式

单例模式的核心是确保只有一个实例,并提供全局访问。

惰性单例


惰性单例是指在需要的时候才创建对象实例。惰性单例是单例模式的重点,这种技术在实际开发中非常有用。

实例:

假设我们是WebQQ的开发人员,当点击左边导航里qq头像时,会弹出一个登陆浮窗,很明显这个浮窗是在页面里总是唯一的,不可能出现两个登陆窗口的情况。


u=457201617,987713994&fm=21&gp=0.jpg
 实现原理:

 用一个变量判断是否已经创建过登陆浮窗;



 代码如下:
var createLoginLayer = (function  () {

var div ;

return function  () {  //惰性单例的主要实现原理是利用闭包的特性!!!

if(!div){

div = document.createElement('div')

div.innerHTML = 'I am login window'

div.style.display = 'none'

document.bodyk.appendChild(div);

}

return div;

}

})();

document.getElementById('loginBtn').onclick = function  () {

var loginLayer = createLoginLayer();

loginLayer.style.display = 'block';

}

通用的惰性单例:


上一个例子我们完成了一个可用的惰性单例,但是我们发现它还有如下一些问题。

如果我们要创建其他唯一的标签如script标签,用来跨域请求必须得如法炮制,把createLoginLayer函数几乎照抄一遍:

var createLoginLayer = (function  () {

var div ;

return function  () {  //惰性单例的主要实现原理是利用闭包的特性!!!

if(!div){

script = document.createElement('script')

script.innerHTML = 'I am login window'

script.style.display = 'none'

document.bodyk.appendChild(script);

}

return script;

}

})();
 这显然是痛苦且不符合可复用的设计模式的。

 那么我们现在开始实现可复用通用的惰性单例。

我们需要把不变的部分隔离出来,先不考虑创建一个div和创建一个script有多少差异,先抽象出来一个逻辑:

用一个变量来标志是否创建过对象,如果是,则在下次直接返回这个创建好的对象:

var obj;

if(!obj)

obj = xxx

开始行动利用高阶函数把函数当做对象传入:

var getSingle = function  (fn) {

var result;

return function  () {

return result || (result = fn.apply(this,arguments));

}

};
还有之前的标签创建函数:
var createLoginLayer = (function  () {

var div ;

return function  () {

if(!div){

div = document.createElement('div')

div.innerHTML = 'I am login window'

div.style.display = 'none'

document.bodyk.appendChild(div);

}

return div;

}

})();
最后的创建:
var createSingleLoginLayer = getSingle(createLoginLayer);

document.getElementById('loginBtn').onclick = function  () {

var loginLayer = createSingleLoginLayer();

loginLayer.style.display = 'block';

}
随便实现一个iframe标签:
var createSingleframe = getSingle(    //这里我们直接放入一个匿名函数惹

function  () {

var iframe = document.createElement('iframe')

document.body.appendChild(iframe)

return iframe

}

)

document.getElementById('loginBtn').onclick = function  () {

var loginLayer = createSingleframe();

loginLayer.style.display = 'block';

}
至此我们大功告成了!!!
补充知识:

jquery的one事件:

当点击 p 元素时,增加该元素的文本大小:

$("p").one("click",function(){

$(this).animate({fontSize:"+=6px"}); });

one 事件只能触发一次,我们可以用惰性单例模式同样实现:

var bindEvent = getSingle(function  () {

document.getElementById('div1').onclick = function  () {

alert('click')

}

return true;

})

var render = function  () {

console.log('start render ...')

bindEvent()

}

render()

render()

render()

小结

--

单例模式是我们学习的第一个模式,我们先学习了传统的单例模式实现,也了解到因为语言的差异性,由更适合JavaScript的实现方法。

在getSingle 函数中,提到了闭包和高阶函数的概念。单例模式是一种简单但非常实用的模式,特别是惰性单例技术,在适合的时候才创建对象,并且只创建唯一的一个。

注:本文是根据JavaScript设计模式与开发实践这本书而总结实现的



作者:颜卿今天Coding了吗
链接:http://www.jianshu.com/p/9c8c8c39ad61
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值