singleton模式,又名单例模式。顾名思义,就是只能实例化一次的类(javascript中没有真正的类,我们通常用函数来模拟类,习惯称之为"伪类")。具体地说,singleton模式,就是在该实例不存在的情况下,可以通过可以方法创建一个类来实现创建类的新实例;如果实例已经存在,它会返回一个该对象的引用。

  接下来我将用一个案列来将singleton模式进行分析。在我们的web网上通常会看到一些图片的放大查看,如下图:

                                                                   

  当我的鼠标碰到图中的帅哥时,它会出现一个放大的图标(这里放大图标有点奇怪= = !),于是我们点击后会出现这样的画面如下图:

                                      

  没错,放大后,就可以看到这个美男子的芳容了。这就是我给大家带来的例子,现在我们对所用到的js进行分析:(html,css部分忽略)

  首先我们编写兼容各版本浏览器的事件函数(参考javascript高级程序设计的事件部分):这个示例中只会用到EventUtil中的adds函数。

    

var EventUtil = {
adds : function(element,type,func){
if(element.addEventListener){
element.addEventListener(type,func,false);
}else if(element.attachEvent){
element.attachEvent("on"+type,func);
}else{
element["on"+type] = func;
}
},
removes : function(element,type,func){
if(element.removeEventListener){
element.removeEventListener(type,func,false);
}else if(element.detachEvent){
element.detachEvent("on"+type,func);
}else{
element["on"+type] = null;
}
},
getEvent : function(event){
return event ? event : window.event;
},
getTarget : function(event){
return event.target || event.srcElement;
},
preventDefault : function(event){
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
}
},
stopPropagation : function(event){
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
} function $(id){
return typeof id === "string" ? document.getElementById(id) : id;
}

  接下来开始设计这个放大的功能。首先你会想到既然我要放大,那我肯定要有放大的图片以及放大图片所盛放的容器。没错,我们创建这些必定会用到一系列的Dom方法,这个稍后会见到。

  当我们每次放大图片的时候有一个地方是不会变的,就是背景阴影和盛放图片的容器。每次都是一个背景的div和一个盛放图片的div对象在我们的浏览器中显示,然后关闭后显示。具体分析就是这个对象可以是唯一的,我只需要将它保存在缓存中,放大的时候将这个对象通过document.body.appendChild()方法将它载入到我们的页面,关闭的时候再使用removeChild()方法将它从页面移除(并不是从缓存移除),那我们如何保证每次调用这个对象时都是第一次调用时的对象呢?(这里说的可能有点复杂,简洁说就是每次都是调用最初的那个对象)。

  这个时候singleton模式就可以很好的解决这个问题。回到刚刚所有的保存在缓存中,我们都很熟悉js等高级语言的垃圾回收机制,它采用引用计数的方式(参考javascript高级程序设计第四章)来进行内存管理。既然我们需要这个对象始终保持唯一,那么就需要将这个对象始终保存在缓存,也就是说不然它被回收,那我们应该怎么做到呢?

  闭包。没错,我们可以采用闭包(singleton模式的建立依赖闭包,这个概念就不提了)。于是我们可以采取如下的方法实现:

var showBig = (function(){
var listen; //作为对象的引用
function initial(){
var listen_2,listen_3;
function createBgShadow(){
//先不考虑这里的代码
}
function createBgCenterDiv(){
//先不考虑这里的代码
}
return{
create : function(){
//先不考虑这里的代码
},
removes : function(){
//先不考虑这里的代码
}
}
}
return{
getShadow : function(){
if(!listen){ //如果listen没有引用这个对象,那么就调用一次initial方法。若引用了,则直接跳过
listen = initial();
}
return listen; //返回这个对象(或者对象的引用)
},
getPic : function(picUrl){
//先不考虑这里的代码
}
}
})();

  上述代码中可以看到,为了保存我要保留在内存中的对象,我使用了一个Listen作为我的监听器(我个人称之为监听器,本意为这个对象的引用)。因为Listen在闭包环境中,当第一次返回Initial()方法后,listen始终带有initial()方法所返回的对象,当第二次或者以后再次调用时,listen并未从内存中消失,因此直接返回内存中的listen即可。

  而我们要返回的是一个背景阴影对象,就可以这么做:

  

function createBgShadow(){
//阴影背景的创建
var shadowBg = document.createElement("div");
shadowBg.setAttribute("id","picShadow");
return shadowBg;
}
function createBgCenterDiv(){
//盛放图片的容器的创建
var shadowBgCenterDiv = document.createElement("div");
shadowBgCenterDiv.setAttribute("id","realDiv");
//放大之后的图片的创建
var shadowBgCenterPic = document.createElement("img");
shadowBgCenterPic.setAttribute("src","");
shadowBgCenterPic.setAttribute("id","realPic");
shadowBgCenterDiv.appendChild(shadowBgCenterPic);
//取消放大的图片(那个×)的创建
var cancel = document.createElement("img");
cancel.setAttribute("id","cancelPic");
cancel.setAttribute("src","img/cancel.png");
shadowBgCenterDiv.appendChild(cancel);
return shadowBgCenterDiv;
}
//注意它们都返回了一个DOM的节点对象。这一步很关键。

  然后将这两个对象保存在Listen_2,listen_3中,同样他们也要和initial()一样,保存在内存中。于是我们可以这么做:

return{
//create()方法将节点加入到html页面
create : function(){
if(!listen_2 || !listen_3){
//listen2保存阴影背景的节点
listen_2 = createBgShadow();
//listen3保存图片以及图片容器的节点
listen_3 = createBgCenterDiv();
}
//由于listen_2和Listen_3也使用闭包,始终保存在内存中,这里也只会创建一次对象
document.body.appendChild(listen_2);
document.body.appendChild(listen_3);
},
//removes()方法将节点移出html页面
removes : function(){
var picShadow = $("picShadow");
var realDiv = $("realDiv");
document.body.removeChild(picShadow);
document.body.removeChild(realDiv);
}
}

  这时候已经很明确了singleton模式的作用,它避免了多次创建重复的对象,将我们可以反复使用的对象只创建一次。我们用listen,listen_2,listen_3来保存了这些我们需要反复使用的对象。singleton模式利用闭包可以更快速的创建我们需要的应用,但是这些对象也会一直保存在我们的内存中,所以singleton模式是有它自己的适用范围的,重点突出一个"单"字。

  简单的总结一下singleton模式:

  1.singleton模式是javascript最基本,最有用的模式之一,它提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码通过单一的变量进行访问。(通过单一的接口进行访问,这里是第一个单例中的create()接口和第二个单例中的getShadow()接口)

  2.singleton模式可以用来划分命名空间,以减少全局变量的泛滥。(上述我们只是用了一个showBig的全局变量)

  3.singleton模式通过js的闭包特性反复引用内存中的同一对象,使运用程序更快速的执行。

  4.singleton模式的弊端在于提供的是一种单点访问,可能导致模块间的强耦合(我们的程序遵守高内聚低耦合的原则)。在选择这种模式的时候应该考虑到这种情况。并不是所有情况都要选择它,而是先分析好。

  完整代码如下(测试时不要忘了修改图片的url):

<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<style type="text/css">
*{margin:0px;padding:0px;}
div.singleton{width:177px;height:110px;margin:100px auto;position:relative;}
img{width:177px;height:110px;}
img.real{display:block;}
img.bigger{position:absolute;top:0px;left:0px;opacity:0}
img.bigger:hover{opacity:1;cursor:pointer;z-index:100;}
#picShadow{background:#555;position:fixed;top:0px;left:0px;width:100%;height:100%;filter:alpha(opacity=70);opacity:0.7;-moz-opacity:0.7;z-index:100;}
#realDiv{position:fixed;top:120px;left:283px;display:block;width:800px;height:400px;z-index:200;}
#realPic{display:block;width:auto;height:auto;max-width:780px;max-height:380px;margin:0 auto;padding:5px;background-color:#fff;}
#cancelPic{display:block;width:auto;height:auto;margin:0 auto;cursor:pointer;}
</style>
</head>
<body>
<div class="singleton">
<img class="real" id="real" src="img/cjy.jpg"/>
<img class="bigger" id="bigger" src="img/bigger.png"/>
</div>
</body>
<script type="text/javascript">
/* 兼容事件对象 */
var EventUtil = {
adds : function(element,type,func){
if(element.addEventListener){
element.addEventListener(type,func,false);
}else if(element.attachEvent){
element.attachEvent("on"+type,func);
}else{
element["on"+type] = func;
}
},
removes : function(element,type,func){
if(element.removeEventListener){
element.removeEventListener(type,func,false);
}else if(element.detachEvent){
element.detachEvent("on"+type,func);
}else{
element["on"+type] = null;
}
},
getEvent : function(event){
return event ? event : window.event;
},
getTarget : function(event){
return event.target || event.srcElement;
},
preventDefault : function(event){
if(event.preventDefault){
event.preventDefault();
}else{
event.returnValue = false;
}
},
stopPropagation : function(event){
if(event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;
}
}
} function $(id){
return typeof id === "string" ? document.getElementById(id) : id;
} //单例
var showBig = (function(){
var listen;
function initial(){
var listen_2,listen_3;
function createBgShadow(){
var shadowBg = document.createElement("div");
shadowBg.setAttribute("id","picShadow");
return shadowBg;
}
function createBgCenterDiv(){
var shadowBgCenterDiv = document.createElement("div");
shadowBgCenterDiv.setAttribute("id","realDiv");
//放大图片
var shadowBgCenterPic = document.createElement("img");
shadowBgCenterPic.setAttribute("src","");
shadowBgCenterPic.setAttribute("id","realPic");
shadowBgCenterDiv.appendChild(shadowBgCenterPic);
//创建取消放大的图片
var cancel = document.createElement("img");
cancel.setAttribute("id","cancelPic");
cancel.setAttribute("src","img/cancel.png");
shadowBgCenterDiv.appendChild(cancel);
return shadowBgCenterDiv;
}
return{
create : function(){
if(!listen_2 || !listen_3){
listen_2 = createBgShadow();
listen_3 = createBgCenterDiv();
}
document.body.appendChild(listen_2);
document.body.appendChild(listen_3);
},
removes : function(){
var picShadow = $("picShadow");
var realDiv = $("realDiv");
document.body.removeChild(picShadow);
document.body.removeChild(realDiv);
}
}
}
return{
getShadow : function(){
if(!listen){
listen = initial();
alert("1");
}
return listen;
},
getPic : function(picUrl){
var realPic = $("realPic");
realPic.setAttribute("src",picUrl);
}
}
})();
//事件处理
//为方便这里不做平稳退化
var bigger = $("bigger");
var gS_1 = showBig;
EventUtil.adds(bigger,"click",function(event){
gS_1.getShadow().create();
gS_1.getPic($("real").src);
//这里做一个关闭检测
if($("cancelPic")){
var cancelPic = $("cancelPic");
EventUtil.adds(cancelPic,"click",function(event){
gS_1.getShadow().removes();
});
}
});
</script>
</html>

  

js中singleton模式解析及运用的更多相关文章

  1. js中State模式的解析及运用

     状态模式,在大的范畴中的定义为当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类.每种编程语言有不同的实现方式,运用的范围也多用于游戏之中. 这里我用javascript来模拟状 ...

  2. 转:JS中生成和解析JSON

    原文地址:JS中生成和解析JSON 1.JS中生成JSON对象的方法: var json = []; var row1 = {}; row1.id= "1"; row1.name ...

  3. js中JSON的解析(将json字符串转化为对象)和序列化(将对象转化为json字符串)(函数的功能一般都挺全的,需要的时候去查看完整函数)

    js中JSON的解析(将json字符串转化为对象)和序列化(将对象转化为json字符串)(函数的功能一般都挺全的,需要的时候去查看完整函数) 一.总结 1.JSON解析:JSON.parse(myJS ...

  4. 由项目浅谈JS中MVVM模式

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.    背景 最近项目原因使用了durandal.js和knock ...

  5. js架构设计模式——由项目浅谈JS中MVVM模式

    1.    背景 最近项目原因使用了durandal.js和knockout.js,颇有受益.决定写一个比较浅显的总结. 之前一直在用SpringMVC框架写后台,前台是用JSP+JS+标签库,算是很 ...

  6. JS中生成和解析JSON

    1.JS中生成JSON对象的方法: var json = []; var row1 = {}; row1.id= "1"; row1.name = "jyy"; ...

  7. js中严格模式

    我们在js中可以使用"use strict";定义了我们在接下来的文档输写中 将按照严格模式进行: function(){ "use strict'; ;// 在这里我们 ...

  8. JS 中Promise 模式

    异步模式在web编程中变得越来越重要,对于web主流语言Javscript来说,这种模式实现起来不是很利索,为此,许多Javascript库(比如 jQuery和Dojo)添加了一种称为promise ...

  9. (转)Spring中Singleton模式的线程安全

    不知道哪里的文章,总结性还是比较好的.但是代码凌乱,有的还没有图.如果找到原文了可以进行替换! spring中的单例 spring中管理的bean实例默认情况下是单例的[sigleton类型],就还有 ...

随机推荐

  1. 【转】char码值对应列表大全

    char("56") A char("97") a [转]char码值对应列表大全 Char("0") 为0的字符Char("1& ...

  2. 分享一下常用的hosts列表

    #以下的hosts能够保证基本的谷歌服务不受影响,其他网站则不一定能够顺利访问,Youtube视频无法播放,但是可以顺利上传视频 #Thanks smarthosts  ,  老夏 ,Humorce  ...

  3. SQL生成一柱双色球

    数据库环境:SQL SERVER 2005 以前用C/JAVA穷举双色球的所有排列,今天想着换成用SQL实现,只生成一柱双色球. 简单说下双色球的规则,双色球由红色球和蓝色球组成,每注投注号码由6个红 ...

  4. 利用c++操作XML,主要是内部循环方法的使用

    本文主要分享的是循环方法的使用,设置XML节点属性,用了3种循环方法. XML文件: <?xml version='1.0' encoding='utf-8' ?><root> ...

  5. C++的函数重载 转

    ——每个现象后面都隐藏一个本质,关键在于我们是否去挖掘 写在前面: 函数重载的重要性不言而明,但是你知道C++中函数重载是如何实现的呢(虽然本文谈的是C++中函数重载的实现,但我想其它语言也是类似的) ...

  6. (三)跟我一起玩Linux网络服务:DHCP服务配置之主服务器配置

    我们今天来做DHCP服务器的配置,我们的前提示要实现用一台虚拟机做DHCP服务器 1.首先,我们要有DHCP软件,我们用到下面两个软件(可以使用其他方法从网上直接安装,具体方法网络搜索) dhcp-3 ...

  7. JavaScript学习总结【6】、JS BOM

    1.BOM 简介 所谓的 BOM 即浏览器对象模型(Browser Object Model).BOM 赋予了 JS 操作浏览器的能力,即 window 操作.DOM 则用于创建删除节点,操作 HTM ...

  8. apache2.4下载与安装

    step1 下载apache 百度“apache下载”,找到官网链接,如下 2. 点进去后选择 Files for microsoft windows,如下 3. 前三个任选一个,这里我们选第一个,如 ...

  9. Python环境搭建中解决C编译的问题

    下载必要文件 Python Microsoft Visual C++ Compiler for Python 2.7 setuptools 安装Python 安装VCForPython27 在命令行下 ...

  10. iOS: 学习笔记, 用代码驱动自动布局实例(swift)

    iOS自动布局是设置iOS界面的利器.本实例展示了如何使用自动布局语言设置水平布局, 垂直布局1. 创建空白iOS项目(swift)2. 添加一个控制器类, 修改YYAppDelegate.swift ...