单体模式的概述:
单体是一个只能被实例化一次而且能够经过一个众所周知的访问点访问的类。
单体是一个用来划分命名空间并将一批相关方法和属性组织在一块儿的对象。若是它能够被实例化,那么他只能被实例化一次。 javascript
单体对象的区分;
1.并不是全部的对象字面量都是单体。若是他只是用来模仿关联数组或容纳数据的话,那就不是单体。
2.若是用来组织一批相关方法和属性话。那就多是单体。
1.单体的基本结构
最简单的单体实际上就是一个对象字面量,它把一批有必定关联的方法和属性组织在一块儿
var Singleton = {
attribute1 : true,
attribute2 : 10,
method1:function(){ java
},
method2:function(){ 程序员
}
} 编程
类分析:
1.这个单体对象被修改。能够为对象添加新成员。
2.可使用delete运算符删除其现有成员。
3.面向对象设计的原则:类能够被扩展,可是不能 被修改。 数组
5.2划分命名空间
单体对象有两部分组成:
包含着方法和属性成员的对象自身。以及用来访问它的变量。(这个变量一般是全局性的,以便在网页上任何地方都能直接访问到它所指向的单体对象。) 这是单体模式的一个要点。
命名空间是可靠的javascript编程的一个重要工具。
为了不无心中改下变量,最好的解决方法之一是用单体对象将代码组织在命名空间之中。
var Mynamespace = {
findProduct : function(id){ 闭包
}
} 函数
分析:
1.如今findProduct函数是一个Mynamespace的中一个方法,不会被全局命名空间中声明的任何新变量改写。
2.用命名空间把相似的方法组织在一块儿。有助于加强代码的文档性。
命名空间进一步分割。
各类javascript代码,都有可能出如今全局命名空间中。
为了不冲突,能够定义一个用来包含本身的全部代码的全局对象:
var GiantCorp = {};
2.而后能够分闷别类地把本身的代码和数据组织到这个全局对象中的各类对象中:
GiantCorp.Common = { 工具
} 网站
5.3 用做特定网页专用代码的包装器的单体
场景描述:
在有不少网页网页的网站中,有些javascript代码是全部的网页都要用到的,因此他们被存放在独立的文件中,有些代码是某个网页专用的。不会被用到其余地方。
建议:最后把这两种代码分别包装在本身的单体对象中。
包装特定网页的专用代码的单体的骨架:
Namespace.PageName = {
CONSTANT_1:true,
CONSTANT_2:10,
method1:function(){ this
},
method2:function(){
}
init:function(){
}
}
5.4拥有私有成员的单体
5.4.1使用下划线表示法
1.在单体对象内建立私有成员最简单,。最直接了当的办法是使用下划线表示法。
2.在单体对象中使用下划线表示法是一种告诫其余程序员不要直接访问特定成员的简明方法
GiantCorp.DataParser = {
_stripWhitespace :function(str){
return str.replace(/\s+/,'');
},
_stringSplit:function(str,delimiter){
return str.split(delimiter)
},
string:function(str,delimiter,stripws){
if(stripws);
str = this.__stripWhitespace(str);
var outputArray = this._stringSplit(str,delimiter);
return outputArray;
}
}
5.4.2 使用闭包
在单体对象中建立私有成员的第二种方法须要借助闭包,这个和第3章中建立真正的私有成员的作法很是类似。可是有一个(重要的区别)
1.以前的作法是吧变量和函数定义在构造函数体内,让他变成私有成员。
2.构造函数体内定义了全部的特权方法并用this关键字使其可被外界访问。
3.每次生成一个该类的实例时,全部的声明的构造函数内的方法和属性都会再次建立一次。
单体模式使用闭包:
1.单体只会被实例化一次。不用担忧本身在构造函数中声明了多少成员。
2.每一个属性和方法都会被建立一次。全部能够把他们声明在构造函数内部
mynamespace.singleton = {};
建立一个定义以后当即执行的函数建立单体:
mynamespace.singleton = function{
return{};
}();
类的做用和分析:
1.第二个例子中并无把一个函数复制给mynamespace.singleton。
2.匿名函数返回类一个对象,而赋给mynamespace.singletion变量的正是这个对象。
3.为了理解执行这个匿名函数,只需在其定义的最后那个大括号后面放上一堆圆括号便可。
5.4.3两种技术的比较
看dataparser例子,看看如何在其实现中使用真正的私有成员,不在是经过下划线为每一个私有方法。
giantcorp.dataparser = (function(){
//私有属性
var while = /\s+/;
//私有方法
function stripwhitespace(str){
return str.replace(while,'');
}
function stringsplit(str,delimiter){
return str.split(delimiter);
}
return {
stringtoarray:function(str,delimiter,stripws){
if(stripws){
str = stripwhitespace(str);
}
}
var outputArray = stringSplit(str,delimiter);
retrun outputArray;
}
})();
类分析:
1.如今这些私有方法和属性能够直接用其名称访问,没必要在其前面加上“this.”或“dataparser.” 这些前缀只用于访问单体对象的公有成员。
这个模式与使用下划线表示法的模式比较的几点优点
1.把私有成员放到闭包中能够确保其不会在单体对象以外被使用。
2.能够自由的改变对象的实现细节。不会殃及别人的代码。
3.这种方法对数据进行保护和封装。
单体模式带来的好处:
1.在使用这种模式时,你能够享受到真正的私有成员带来的全部好处。
2.单体类只会被实例化一次。
3.单体模式是javascript种最流行、应有最普遍的模式之一。
5.5惰性实例化:
前面所讲的单体模式的各类方法实现方式有一个共同点:
1.单体对象都是在脚本加载时被建立出来
2.对于资源密集型的或配置开销甚大的单体,在须要用到的才建立对象。这个技术被称为懒惰加载。
3.做为命名空间。特定网页专用的代码包装器或者组织相关实用的方法仍是当即加载。
4.懒惰加载单体的特别之处。访问他们必须借助于一个静态。
调用方式:Singleton.geninstance().methodname()而不是这样调用:singleton.methodname().
5.getinstace方法会检查该单体是否已经被实例化。若是没有。那么它将建立并返回其实例。已经实例化就会返回如今的实例。
6. 把普通的单体转化为惰性加载单体:
mynamespace.singleton = (function(){
var privateAttribute1 = false;
var privateAttribute2 = [1,2,3];
function privateMethod1(){
}
function privateMethod2(args){
}
return {
publicAttribute1 : true,
publicAttribute2 : 10,
publicMethod1 : function(){
},
publicMethod2 : function(){
}
}
})()
转化第一步:把单体的全部代码移到一个名为constructor方法中:
mynamespace.singleton = (function(){
function constructor(){
var privateAttribute1 = false;
var privateAttribute2 = [1,2,3];
function privateMethod1(){
}
function privateMethod2(args){
}
return {
publicAttribute1 : true,
publicAttribute2 : 10,
publicMethod1 : function(){
},
publicMethod2 : function(){
}
}
}
})()
类分析:
1. 这个方法不能从闭包外部访问,因此咱们能够全权控制器调用时机。
2.公有方法getInstances是用来控制实现这种控制。
3.getInstace要变成公有方法,须要放到一个对象字面量返回对象便可;
examples:
mynamaespace.singleton = (function(){
function constructor (){
}
return {
getinstace:{
}
}
})()
编写用于控制单体类的实例化时机的代码,须要中两件事:
1.必须知道该类是否被实例化过。
2.若是该类已经被实例化过。那么他须要掌握其实力的状况,以便能返回这个实例
3.办这两件事须要用一个私有属性的已有的私有方法constructor
mynamespace.singleton = (function(){
var uniqueInstace;
function constructor(){}
return {
getInstace : function(){
if(uniqueinstace){
uniqueInstace = constructor();
}
return uniqueInstace;
}
}
})()
调用方式:mynamespace.singleton.getinstace().publicmethod1();
命名空间太长简化分: var mns = mynamespace.singleton;
5.6分支
5.8单体模式的适应场合 1。从未代码的提供命名空间和加强模块的角度来讲,应该尽可能多使用单体模式。 2.