JavaScript设计模式:单体模式
单体模式:
@单体模式用于创建命名空间,将系列关联的属性和方法组织成一个逻辑单元,减少全局变量。
逻辑单元中的代码通过单一的变量进行访问。
@一个单体对象由对象本身 和 访问这个对象的变量组成。
此变量通常为全局变量,所以单体对象能在页面任何位置被访问,故此变量可看做单体对象内部属性和方法的一个命名空间。
@三个特点:
① 该类只有一个实例;
② 该类自行创建该实例,即在该类内部创建自身的实例对象;
③ 向整个系统公开这个实例接口。
@单体弊端:
耦合度高,不好单元测试。
@适合场合:
提供命名空间,增加代码模块性,惰性加载,分支功能。
1、基本结构:
var Singleton = { attr1 : 1, attr2 : 'hello', method1 : function(){alert(this.attr2);}, method2 : function(arg){} }
1.1上例的方式,对象Singleton的所有成员是公开的,在执行到变量Singleton时,会加载(实例化)自身,即非惰性加载。
1.2method1中用this访问单体的其他成员会存在一些风险,因为method1的上下文不是总指向Singleton对象。
如,当方法绑定到事件监听器时,this指向dom元素而失效,这时会提示undefined,故最好使用单体对象的全名访问属性和方法。
2、闭包 实现私有成员的单体,亦称为模块模式(module pattem)
2.1闭包函数 返回的是一个字面量作为单体对象。在继承中返回的是一个构造函数,思路是一样的,利用闭包。
2.2单体模式非常适合使用闭包实现私有方法,因为单体只会实例化一次,没有每次实例化都需要一份私有成员占用内存的顾虑。
var Singleton = (function(){ var attr = 1,
fn = function(){}; return { //return的都是公有成员,其他私有 method : function(){ fn(); }, getAttr : function(){ return attr; } }; })();
2.3因为单体会被实例化一次,故构造函数中声明的所有成员值会被创建一次。
上例,关键字var定义了私有成员,返回了一个公开的接口method和getAttr。
今后,修改实现时只需修改私有成员,method和getAttr接口不变。
3、闭包实现私有成员的惰性实例化单体,惰性实例化(lazy Instantiation)/惰性加载
3.1前面提到的单体模式的实现 都是在脚本加载时即创建的。当一个单体对象需要加载大量数据时,在需要时再创建单体对象会更好。
3.2单体放在constructor()函数中,getInstance函数用于控制单体加载。
使用形式:MyNamespace.Singleton.getInstance().publicMethod1();
对于长的命名空间可以用别名,var MNS = MyNamespace.Singleton; 可使用别名代替this!
上述,用于需要大量数据的单体 直到需要时才实例化。对于命名空间、特定网页专用代码 和 实用的工具方法不使用。
缺点:代码复杂,不直观。
3、分支技术Branching:将浏览器之间的差异封装到动态方法,适用于解决浏览器之间的差异。
通过return (someCondition) ? objectA : objectB;3
缺点:分支中,objectA 和 objectB都被创建了,并保存在内存中了,但只用到一个。
需要在 计算时间 和 占用内存 两者中取舍。