文档章节

javaScript设计模式系列(二) 单体模式

Say_-no
 Say_-no
发布于 2017/06/27 15:28
字数 1288
阅读 12
收藏 1

什么是单体模式

一讲到概念我们的第一反应就是WTF

 

 

 

 

 

 

 

 

 

其实单体模式是最常用,也是最有用的一种模式。而我们也会在项目中不知不觉的写一些单体模式,只是我们没有意识到,这也是一种设计模式。看一个简单的例子:

var zoom = {
  bird: 10,
  monkey: 10,
  play: function() {},
  eat: function() {}
}

这和我随手找的一个对象有什么区别,从严格意义上讲这确实不能称为一个单体。但我们可以分析一下这个对象,其中有两个zoom相关的属性,和两个zoom相关的方法。实际上最简单的单体就是字面量,它是把一些有一定关系的方法和属性组织在一起。

但他违背了面向对象设计的一条原则:类可以被扩展,但不应该被修改。听到这里我们也不需要慌,因为(Python,Ruby)都允许在定义了类之后对其修改。

可能你还是不知道单体与普通字面量有什么不同,那就再看一个例子:

var zoom = function() {
  var bird = 10;
  var monkey = 10;
  this.play = function() {}
  this.eat = function() {}
}
var zoom1 = new zoom();
var zoom2 = new zoom();
console.log(zoom1 === zoom2)//false;

zoom被实例化两次,但两个实例明显不相等。因为zoom1,zoom2的指针,并没有只向内存中的同一地址。这也正好可以引出单体与不同字面量的不同。按传统定义,单体是一个只能被实例化一次,并且可以通过一个众所周知的访问点访问的对象。后半句简单说,就是可以全局访问。

总结一下上面所讲。单体是一个用来划分命名空间并将一批相关方法和属性组织在一起的对象,如果它可以被实例化,那么它只能被实例化一次。

与命名空间的关系

如果我们的变量都定义在全局中,一不小心别人重新用相同的变量名,定义一个变量,那我们的代码就会出问题,而且这种问题很难排查。为了避免这种不确定性,我们可以把代码组织在命名空间中(其实,就是另一个对象中,但这个对象,更具有包含性)

var ZoomSpace = {
  otherFunction: function() {}
}
ZoomSpace.zoomUtil = {
  bird: 10,
  monkey: 10,
  play: function() {},
  eat: function() {}
}

这样如果在全局中重定义了zoomUtil,我们的zoomUtil也不会受到影响。

使用构造函数

function zoomUtil() {
  //如果被实例化过,就返回实例化的结果
  if(zoomUtil.unique !== undefined) {
    return zoomUtil.unique;
  }
  var bird = 10;
  var monkey = 10;
  function play() {};
  function eat(){};
  return zoomUtil.unique = this;
}
var zoom1 = new zoomUtil();
var zoom2 = new zoomUtil();
console.log(zoom1 === zoom2)//true

这种方式比较简洁,通过判断是否已经实例化过,但是也没啥安全性,如果在外部修改zoomUtil.unique 那很可能单例模式就被破坏了。

拥有私有成员的单体

使用下划线表示

下划线表示私有成员,是约定俗称的一种方法,告诉别人不要直接访问私有方法。

使用上面我们已经定义好的命名空间:

ZoomSpace.zoomUtil = {
  bird: 10,
  monkey: 10,
  _runTime: function() {
    return ++this.bird;
  },
  play: function() {
    //return this._runTime(); 尽量不要再共有方法中使用this
    //this很可能因为此方法使用在别的函数中导致指向window
    return ZoomSpace.zoomUtil._runTime();
  },
  eat: function() {}
}
console.log(ZoomSpace.zoomUtil.play());//11

这种方法的安全性也不好,主要靠人为的约束,但是如果有人非要用我们的私有方法,导致我们删除或者修改私有方法后,他的程序不能用,只能能跟他说no zuo no die。

使用闭包

之前我们的单体都是这样的:

ZoomSpace.zoomUitl = {};

现在我们用一个立即执行的函数创建,像这样:

ZoomSpace.zoomUitl = (function(){
  return {};
})();

之前的方法是把变量和函数定义在构造函数内部。因此,每次生成一个实例,所有的方法属性都会被再次创建。这样的做法很低效。而现在的做法我们不必要担心定义的属性过多,因为它只会被实例化一次。我们来改写上面的例子:

ZoomSpace.zoomUtil = (function(){
  //私有属性和方法
  var bird = 10;
  var monkey = 10;
  function runTime(){
    return ++bird;//不需要使用this
  };
  function otherFunction(){} //最后一个大括号之后不需要再加;
  return {
    play:function(){
      return runTime();
    }
  }
})()
console.log(ZoomSpace.zoomUtil.play());//11

如果你想通过new的方式来写,可以像下面这样修改:

ZoomSpace.zoomUtil = (function() {
  //私有属性和方法
  var unique;
  function zoomUtilConstructor() {
    if(unique !== undefined) {
      return unique;
    }
    var bird = 10;
    var monkey = 10;
    function runTime() {
      return ++bird;
    };
  }
  return unique = zoomUtilConstructor;
})()
var zoom1 = new ZoomSpace.zoomUtil();
var zoom2 = new ZoomSpace.zoomUtil();
console.log(zoom1 === zoom2); //true

方法有很多,具体看那种最适合。

总结

考虑否严格的只需要一个实例对象的类,那么就要考虑使用单体模式。使用数据缓存来存储该单例,用作判断单例是否已经生成,是单例模式主要的实现思路。

© 著作权归作者所有

Say_-no
粉丝 1
博文 6
码字总数 9308
作品 0
昆明
私信 提问
《JavaScript设计模式与开发实践》最全知识点汇总大全

系列文章: 《JavaScript设计模式与开发实践》基础篇(1)—— this、call 和 apply 《JavaScript设计模式与开发实践》基础篇(2)—— 闭包和高阶函数 《JavaScript设计模式与开发实践》模式...

嗨呀豆豆呢
01/04
0
0
《JavaScript设计模式与开发实践》原则篇(2)—— 最少知识原则

最少知识原则(LKP)说的是一个软件实体应当尽可能少地与其他实体发生相互作用。这 里的软件实体是一个广义的概念,不仅包括对象,还包括系统、类、模块、函数、变量等。 单一职责原则指导我们...

嗨呀豆豆呢
2018/12/30
0
0
《JavaScript设计模式与开发实践》模式篇(12)—— 装饰者模式

在传统的面向对象语言中,给对象添加功能常常使用继承的方式,但是继承的方式并不灵活, 还会带来许多问题:一方面会导致超类和子类之间存在强耦合性,当超类改变时,子类也会随之 改变;另一方...

嗨呀豆豆呢
2018/12/25
0
0
《JavaScript设计模式与开发实践》模式篇(6)—— 命令模式

命令模式是最简单和优雅的模式之一,命令模式中的命令(command)指的是一个执行某些特定事情的指令。 应用场景 有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求...

嗨呀豆豆呢
2018/12/15
0
0
《JavaScript设计模式与开发实践》模式篇(11)—— 中介者模式

中介者模式的作用就是解除对象与对象之间的紧耦合关系。增加一个中介者对象后,所有的 相关对象都通过中介者对象来通信,而不是互相引用,所以当一个对象发生改变时,只需要通知 中介者对象即...

嗨呀豆豆呢
2018/12/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

centos7 linuxdeployqt qt5.13.1 打包程序

原文链接:https://www.cnblogs.com/linuxAndMcu/p/11016322.html 一、简介 linuxdeployqt 是Linux下的qt打包工具,可以将应用程序使用的资源(如库,图形和插件)复制到二进制运行文件所在的...

shzwork
6分钟前
1
0
IDEA 配置Springboot项目热部署

实现的方式概述 注意以下的热部署方式在IDEA是默认没有打开自动编译的,手动编译需要快捷键(Ctrl+Shift+F9),自动编译的修改配置如下:(注意刷新不要太快,会有1-2秒延迟) File-Settings-C...

小强的进阶之路
17分钟前
4
0
免费数据分析工具:secsoso

前段时间思考了理想数据分析平台,之后我们根据这个思路开发了spl语言并提供了一个数据分析平台,这个平台主要用在搜索ES,数据库索引中的数据。但后来发现对文件的事后处理也是个非常重要的...

赛克蓝德
19分钟前
2
0
暗黑2不能正常启动?带你轻松使用WIN10运行游戏

暗黑破坏神2这款游戏由于年代比较久远,所以设置启动这方面与现在的大部分游戏有很大差距,由于当初完美运行暗黑2是当年使用最多的XP系统,在使用现在大多数玩家使用的WIN7到WIN10系统常会出...

太空堡垒185
23分钟前
3
0
maven项目对象模型(二)

1.4.4.传递性依赖 一个传递性依赖就是一个依赖的依赖。如果project-a依赖于project-b,而后者接着依赖于project-c,那么project-c就是被认为是project-a的传递性依赖。如果project-c依赖于p...

万建宁
23分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部