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

来源:互联网 发布:北京供销大数据集团 编辑:程序博客网 时间:2024/06/07 01:53

设计模式(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
原创粉丝点击