javascript设计模式之单体模式学习笔记


Posted in Javascript onFebruary 15, 2017

单体模式提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码可以通过单一变量进行访问。

单体模式的优点是:

  • 可以用来划分命名空间,减少全局变量的数量。
  • 使用单体模式可以使代码组织的更为一致,使代码容易阅读和维护。
  • 可以被实例化,且实例化一次。

什么是单体模式?单体模式是一个用来划分命名空间并将一批属性和方法组织在一起的对象,如果它可以被实例化,那么它只能被实例化一次。

但是并非所有的对象字面量都是单体,比如说模拟数组或容纳数据的话,那么它就不是单体,但是如果是组织一批相关的属性和方法在一起的话,那么它有可能是单体模式,所以这需要看开发者编写代码的意图;

下面我们来看看定义一个对象字面量(结构类似于单体模式)的基本结构如下:

// 对象字面量
var Singleton = {
  attr1: 1,
  attr2: 2,
  method1: function(){
    return this.attr1;
  },
  method2: function(){
    return this.attr2;
  }
};

如上面只是简单的字面量结构,上面的所有成员变量都是通过Singleton来访问的,但是它并不是单体模式;因为单体模式还有一个更重要的特点,就是可以仅被实例化一次,上面的只是不能被实例化的一个类,因此不是单体模式;对象字面量是用来创建单体模式的方法之一;

使用单体模式的结构如下demo

我们明白的是单体模式如果有实例化的话,那么只实例化一次,要实现一个单体模式的话,我们无非就是使用一个变量来标识该类是否被实例化,如果未被实例化的话,那么我们可以实例化一次,否则的话,直接返回已经被实例化的对象。

如下代码是单体模式的基本结构:

// 单体模式
var Singleton = function(name){
  this.name = name;
  this.instance = null;
};
Singleton.prototype.getName = function(){
  return this.name;
}
// 获取实例对象
function getInstance(name) {
  if(!this.instance) {
    this.instance = new Singleton(name);
  }
  return this.instance;
}
// 测试单体模式的实例
var a = getInstance("aa");
var b = getInstance("bb");
// 因为单体模式是只实例化一次,所以下面的实例是相等的
console.log(a === b); // true

由于单体模式只实例化一次,因此第一次调用,返回的是a实例对象,当我们继续调用的时候,b的实例就是a的实例,因此下面都是打印的是aa;

console.log(a.getName());// aa
console.log(b.getName());// aa

上面的封装单体模式也可以改成如下结构写法:

// 单体模式
var Singleton = function(name){
  this.name = name;
};
Singleton.prototype.getName = function(){
  return this.name;
}
// 获取实例对象
var getInstance = (function() {
  var instance = null;
  return function(name) {
    if(!instance) {
      instance = new Singleton(name);
    }
    return instance;
  }
})();
// 测试单体模式的实例
var a = getInstance("aa");
var b = getInstance("bb");
// 因为单体模式是只实例化一次,所以下面的实例是相等的

console.log(a === b); // true

console.log(a.getName());// aa

console.log(b.getName());// aa

理解使用代理实现单列模式的好处

比如我现在页面上需要创建一个div的元素,那么我们肯定需要有一个创建div的函数,而现在我只需要这个函数只负责创建div元素,其他的它不想管,也就是想实现单一职责原则,就好比淘宝的kissy一样,一开始的时候他们定义kissy只做一件事,并且把这件事做好,具体的单体模式中的实例化类的事情交给代理函数去处理,这样做的好处是具体的业务逻辑分开了,代理只管代理的业务逻辑,在这里代理的作用是实例化对象,并且只实例化一次; 创建div代码只管创建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 ProxyMode = (function(){
  var instance;
  return function(html) {
    if(!instance) {
      instance = new CreateDiv("我来测试下");
    }
    return instance;
  } 
})();
var a = new ProxyMode("aaa");
var b = new ProxyMode("bbb");
console.log(a===b);// true

理解使用单体模式来实现弹窗的基本原理

下面我们继续来使用单体模式来实现一个弹窗的demo;我们先不讨论使用单体模式来实现,我们想下我们平时是怎么编写代码来实现弹窗效果的; 比如我们有一个弹窗,默认的情况下肯定是隐藏的,当我点击的时候,它需要显示出来;如下编写代码:

// 实现弹窗
var createWindow = function(){
  var div = document.createElement("div");
  div.innerHTML = "我是弹窗内容";
  div.style.display = 'none';
  document.body.appendChild('div');
  return div;
};
document.getElementById("Id").onclick = function(){
  // 点击后先创建一个div元素
  var win = createWindow();
  win.style.display = "block";
}

如上的代码;大家可以看看,有明显的缺点,比如我点击一个元素需要创建一个div,我点击第二个元素又会创建一次div,我们频繁的点击某某元素,他们会频繁的创建div的元素,虽然当我们点击关闭的时候可以移除弹出代码,但是呢我们频繁的创建和删除并不好,特别对于性能会有很大的影响,对DOM频繁的操作会引起重绘等,从而影响性能;因此这是非常不好的习惯;我们现在可以使用单体模式来实现弹窗效果,我们只实例化一次就可以了;如下代码:

// 实现单体模式弹窗
var createWindow = (function(){
  var div;
  return function(){
    if(!div) {
      div = document.createElement("div");
      div.innerHTML = "我是弹窗内容";
      div.style.display = 'none';
      document.body.appendChild(div);
    }
    return div;
  }
})();
document.getElementById("Id").onclick = function(){
  // 点击后先创建一个div元素
  var win = createWindow();
  win.style.display = "block";
}

理解编写通用的单体模式

上面的弹窗的代码虽然完成了使用单体模式创建弹窗效果,但是代码并不通用,比如上面是完成弹窗的代码,假如我们以后需要在页面中一个iframe呢?我们是不是需要重新写一套创建iframe的代码呢?比如如下创建iframe:

var createIframe = (function(){
  var iframe;
  return function(){
    if(!iframe) {
      iframe = document.createElement("iframe");
      iframe.style.display = 'none';
      document.body.appendChild(iframe);
    }
    return iframe;
  };
})();

我们看到如上代码,创建div的代码和创建iframe代码很类似,我们现在可以考虑把通用的代码分离出来,使代码变成完全抽象,我们现在可以编写一套代码封装在getInstance函数内,如下代码:

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

如上代码:我们使用一个参数fn传递进去,如果有result这个实例的话,直接返回,否则的话,当前的getInstance函数调用fn这个函数,是this指针指向与这个fn这个函数;之后返回被保存在result里面;现在我们可以传递一个函数进去,不管他是创建div也好,还是创建iframe也好,总之如果是这种的话,都可以使用getInstance来获取他们的实例对象;

如下测试创建iframe和创建div的代码如下:

// 创建div
var createWindow = function(){
  var div = document.createElement("div");
  div.innerHTML = "我是弹窗内容";
  div.style.display = 'none';
  document.body.appendChild(div);
  return div;
};
// 创建iframe
var createIframe = function(){
  var iframe = document.createElement("iframe");
  document.body.appendChild(iframe);
  return iframe;
};
// 获取实例的封装代码
var getInstance = function(fn) {
  var result;
  return function(){
    return result || (result = fn.call(this,arguments));
  }
};
// 测试创建div
var createSingleDiv = getInstance(createWindow);
document.getElementById("Id").onclick = function(){
  var win = createSingleDiv();
  win.style.display = "block";
};
// 测试创建iframe
var createSingleIframe = getInstance(createIframe);
document.getElementById("Id").onclick = function(){
  var win = createSingleIframe();
  win.src = "http://www.3water.com";
};

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery 入门教程 [翻译] 推荐
Aug 17 Javascript
jQuery Tools tooltip使用说明
Jul 14 Javascript
JS幻灯片可循环播放可平滑旋转带滚动导航(自写)
Aug 05 Javascript
SuperSlide2实现图片滚动特效
Jun 20 Javascript
Javascript设计模式理论与编程实战之简单工厂模式
Nov 03 Javascript
最细致的vue.js基础语法 值得收藏!
Nov 03 Javascript
详解webpack和webpack-simple中如何引入css文件
Jun 28 Javascript
jQuery实现的简单图片轮播效果完整示例
Feb 08 jQuery
微信小程序实现图片上传放大预览删除代码
Jun 28 Javascript
Vue项目引进ElementUI组件的方法
Nov 11 Javascript
vue.js指令v-for使用以及下标索引的获取
Jan 31 Javascript
vue中使用mockjs配置和使用方式
Apr 06 Vue.js
JavaScript中的toString()和toLocaleString()方法的区别
Feb 15 #Javascript
javascript设计模式之模块模式学习笔记
Feb 15 #Javascript
javascript设计模式之策略模式学习笔记
Feb 15 #Javascript
BootStrap实现带关闭按钮功能
Feb 15 #Javascript
Jil,高效的json序列化和反序列化库
Feb 15 #Javascript
Bootstrap模态框使用详解
Feb 15 #Javascript
js时间戳和c#时间戳互转方法(推荐)
Feb 15 #Javascript
You might like
php生成随机数或者字符串的代码
2008/09/05 PHP
对squid中refresh_pattern的一些理解和建议
2009/04/17 PHP
php中关于换行的实例写法
2019/09/26 PHP
JObj预览一个JS的框架
2008/03/13 Javascript
关于IE、Firefox、Opera页面呈现异同 写脚本很痛苦
2009/08/28 Javascript
由JavaScript技术实现的web小游戏(不含网游)
2010/06/12 Javascript
JavaScript 打地鼠游戏代码说明
2010/10/12 Javascript
用dtree实现树形菜单 dtree使用说明
2011/10/17 Javascript
Extjs中通过Tree加载右侧TabPanel具体实现
2013/05/05 Javascript
jQuery+css实现百度百科的页面导航效果
2014/12/16 Javascript
Jquery基础教程之DOM操作
2015/08/19 Javascript
关于Javascript中document.cookie的使用
2017/03/08 Javascript
DVA框架统一处理所有页面的loading状态
2017/08/25 Javascript
一步步教你利用Canvas对图片进行处理
2017/09/19 Javascript
JQuery 选择器、DOM节点操作练习实例
2017/09/28 jQuery
小程序click-scroll组件设计
2019/06/18 Javascript
Angular8引入百度Echarts进行图表分析的实现代码
2019/11/27 Javascript
js实现视图和数据双向绑定的方法分析
2020/02/05 Javascript
JavaScript如何判断input数据类型
2020/02/06 Javascript
[04:19]完美世界携手游戏风云打造 卡尔工作室模型介绍篇
2013/04/24 DOTA
使用 Python 获取 Linux 系统信息的代码
2014/07/13 Python
Python素数检测的方法
2015/05/11 Python
python绘图方法实例入门
2015/05/19 Python
Python常用知识点汇总
2016/05/08 Python
Python基础语言学习笔记总结(精华)
2017/11/14 Python
Python实现的调用C语言函数功能简单实例
2019/03/13 Python
详解python之heapq模块及排序操作
2019/04/04 Python
Python坐标轴操作及设置代码实例
2020/06/04 Python
电影T恤、80年代T恤和80年代服装:TV Store Online
2020/01/05 全球购物
乱丢垃圾袋检讨书
2014/10/08 职场文书
钢琴师观后感
2015/06/12 职场文书
劳保用品管理制度范本
2015/08/06 职场文书
2016年学校招生广告语
2016/01/28 职场文书
2019新员工心得体会
2019/06/25 职场文书
导游词之西递宏村
2019/12/10 职场文书
Python接口自动化之文件上传/下载接口详解
2022/04/05 Python