JavaScript设计模式-单例模式、模块模式(转载 学习中。。。。)
(转载地址:http://technicolor.iteye.com/blog/1409656)
之前在《JavaScript小特性-面向对象》里面介绍过JavaScript面向对象的特性了,有了面向对象之后,自然就会想——那是不是还有设计模式呢?由于js面向对象的方式是基于原型(prototype)的,而不是传统基于类型(class),所以js的设计模式也和经典的设计模式有些差异。
关于设计模式
先说说什么是设计模式吧。很多人都觉得“设计模式”这东西很玄乎,把Gof四人帮的《Design Patterns》奉为编程圣经,而我却觉得大可不必。设计模式说白了,就是在特定环境下解决某类常见问题的一种套路,按着这种套路去做就会很得心应手。但是,这并不代表这些设计模式是放之四海皆准,更不是说套着设计模式做的东西就一定是最好维护、性能最佳、至高无上的了。就算你不知道什么设计模式,只要思路正确,也能写出设计模式来。
有大师说,设计模式其实是对语言缺陷的一种弥补。这里有两层意思,一是说设计模式是基于语言的,因为语言存在缺陷,能力有所不足,所以需要设计模式去提供一种通用的解决方式去弥补这些不足;二是说,如果脱离具体语言及具体环境,生搬硬套设计模式甚至会是一种束缚,设计模式并非绝对正确。
了解了上面的观点之后,下面就通过js的单例模式来看看,JavaScript的设计模式是怎么回事。
单例模式(Singleton)
传统的单例模式大概是这么回事(Java版):
- public class Singleton{
- private static Singleton instance;
- private int property;//某些属性
- private Singleton(){
- //通过私有的构造函数来保证只有一个实例
- }
- public static synchronized Singleton getInstance(){
- if (instance == null) {
- instance = new Singleton();
- }
- return instance;
- }
- public void method(){//某些方法}
- }
- var jsSingleton = {
- property:"something",
- method:function(){
- console.log('hello world');
- }
- }
调用也很简单,无需顾及什么类名,任何地方访问jsSingleton都是同一个对象,完全不用担心。如果你气急败坏的跟我说,你这只是饿汉式的,懒汉式单例呢?如果真的创建对象时很耗费资源,或者是你对性能洁癖到一定程度,那也只能让js东施效颦的学一下传统的方式了:
- var jsLazySingleton =(function(){
- var instance;
- //利用闭包来解决私有构造函数的问题(后面有解释)
- function init (){
- return {
- property: 'some thing',
- method: function(){}
- }
- }
- return {
- getInstance :function(){
- //如果instance存在则返回,不存在则调用init()
- return instance || instance = init();
- }
- }
- })();
模块模式(Module)
在js的懒汉式单例模式中,其实也用到了另一种设计模式,即模块模式。在传统软件工程中,模块模式被定义为给类提供私有和公共封装的一种方法,也就是我们常说的“模块化”。在Java里面Class就是一种模块,解决了属性、方法的封装问题,它的模块模式直接就融合到语言特性里面了,因此也没什么模块模式的说法;然而对于JavaScript这种过于灵活的语言,这种最基本的私有化封装却需要用一个设计模式来解决了。
在JavaScript中,“private”是作为保留字,而不是关键字的,也就是说,JavaScript没有私有化这一功能(纠结吧)。解决解决这问题有两种方法,一是定义变量的时候在前面加上下划线“_”,也就是告诉其他开发者,不要动这个变量哟;另一种则是利用闭包。第一种方法并不是真正的私有,只是一种规范,如果要做到真正的私有,还是要用第二种方法——闭包。
我们创建一个匿名函数,然后立即运行它,此匿名函数中的所有代码都存在于一个“闭包”之中,从而得到私有性,并在特定作用域中保持可被访问。方法如下:
- (function () {
- //此作用域的所有变量、函数依旧可在特定作用域中被访问
- })();
- (function( window, undefined ) {
- ......
- //最后一行
- window.jQuery = window.$ = jQuery;
- })(window);
弄清楚这些之后,我们就来看看js模块模式的基本样子吧:
- var Module = (function () {
- var my={},
- privateVar = 8;//私有属性
- function privateFun() {//私有方法
- return ++privateVar;
- };
- my.publicVar = 1;//公共属性
- my.moduleFun = function () {//公共方法
- return privateFun();
- };
- return my;
- }());
- console.log(Module.publicVar);//1
- console.log(Module.publicFun());//9
好了,模块模式解决了JavaScript私有化的问题,我们可以利用它来定义命名空间、单例、拥有私有化封装的对象等等。然而模块模式也并非尽善尽美。例如,我们定义私有、公共变量的方法是不同的,当开发过程中我们需要改变某个变量的可见性的时候,就不得不在它所有出现过的地方进行修改;并且JavaScript作为动态编译的语言,我们可以随时给对象添加属性、方法,然而我们在闭包之外定义的方法是无法直接访问私有数据的。
更高级的模块模式
虽然前面提到的模块模式对于大多数开发者来说已经足够了,但是模块模式还可以被改进的更加强大、更加易于扩展。
扩展性
之前所说的模板模式有一个限制,就是整个模板必须定义在一个文件中。曾面对一大堆代码工作的人肯定明白将它划分为多个文件的意义。好在,有个巧妙的方法来扩展我们的Modules。首先,在匿名函数的参数中导入Module,然后给它添加属性,然后再导出它。下面这个例子是在另一个文件中对上面提到的Module进行扩展(必须是全局作用域的情况):
- var Module = (function (my) {
- my.anotherFun = function () {
- // do someting...
- };
- return my;
- }(Module||{}));//注意,这里还有个“{}”
跨文件私有属性共享
目前的多文件扩展Module还有个一严重的限制,那就是每个文件的Module都只保持自己的私有状态,无法访问其他文件的私有属性。当然,这也可以被解决。下面是解决多文件私有属性共享的一个方法:
- var MODULE = (function () {
- //将所有的私有属性、方法都定义在_private对象中
- //每个扩展Module都可以通过my._private来访问
- var my = {},
- _private = my._private = {},
- _seal = function (){
- //密封,删除所有私有数据的可访问性
- delete my._private;
- },
- _unseal = function (){
- //解封,让私有数据重新可访问
- my._private = _private;
- };
- my.extend = function(otherModules){
- //必须通过此方法来添加扩展Module文件
- _unseal();
- //add other modules
- _seal();//异步调用,此处只是示意,真正的代码并非如此
- }
- return my;
- }());
上面的Module文件必须第一个被加载,然后利用Module.extend来加载其他的扩展。my.extend实际上是通过类似Labjs的工具来并行加载其他的Module。每个扩展Module都通过my._private来传递私有性,并且都需要将传来的my._private保存为自己的私有属性,所有对my._private的修改都将反应到其他扩展Module中去。此方法参考于Ben Cherry的《JavaScript Module Pattern: In-Depth》。
小结一下
看完了JavaScript的单例模式和模块模式,是不是有点感叹与JavaScript设计模式的不伦不类呢?这些就是语言特性的体现,设计模式是依赖于语言特性的,是对语言能力的一种补充。JavaScript的设计模式并非不伦不类,很多JavaScript也有很多优雅的设计模式,可以让传统设计模式相形见绌的。
接下来还打算写几篇关于JavaScript设计模式的文章,敬请期待。
JavaScript设计模式-单例模式、模块模式(转载 学习中。。。。)的更多相关文章
- JavaScript设计模式之策略模式(学习笔记)
在网上搜索“为什么MVC不是一种设计模式呢?”其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composite).所以我今天选 ...
- 探索Javascript设计模式---单例模式
最近打算系统的学习javascript设计模式,以便自己在开发中遇到问题可以按照设计模式提供的思路进行封装,这样可以提高开发效率并且可以预先规避很多未知的问题. 先从最基本的单例模式开始. 什么是单例 ...
- 从ES6重新认识JavaScript设计模式(三): 建造者模式
1 什么是建造者模式? 建造者模式(Builder)是将一个复杂对象的构建层与其表示层相互分离,同样的构建过程可采用不同的表示. 建造者模式的特点是分步构建一个复杂的对象,可以用不同组合或顺序建造出不 ...
- JavaScript设计模式之----组合模式
javascript设计模式之组合模式 介绍 组合模式是一种专门为创建Web上的动态用户界面而量身制定的模式.使用这种模式可以用一条命令在多个对象上激发复杂的或递归的行为.这可以简化粘合性代码,使其更 ...
- JavaScript设计模式之命令模式【命令解耦】
在讲解命令模式之前我们先来了解一个生活中的命令模式场景: 场景1: 医院看病抓药: 当你因为肾虚到医院看医生,医生一番操作之后得出结论:要吃个疗程[夏桑菊].[小柴胡](药名纯属虚构,真的肾虚就找医生 ...
- 【设计模式】【应用】使用模板方法设计模式、策略模式 处理DAO中的增删改查
原文:使用模板方法设计模式.策略模式 处理DAO中的增删改查 关于模板模式和策略模式参考前面的文章. 分析 在dao中,我们经常要做增删改查操作,如果每个对每个业务对象的操作都写一遍,代码量非常庞大. ...
- 再起航,我的学习笔记之JavaScript设计模式08(建造者模式)
我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 前几 ...
- 再起航,我的学习笔记之JavaScript设计模式17(模板方法模式)
模板方法模式 由模板方法模式开始我们正式告别结构型设计模式,开始行为型设计模式的学习分享 行为型设计模式用于不同对象之间职责划分或算法抽象,行为型设计模式不仅仅涉及类和对象,还涉及类或对象之间的交流模 ...
- 再起航,我的学习笔记之JavaScript设计模式09(原型模式)
我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 我们 ...
随机推荐
- 杭电1170 Balloon Comes
Problem Description The contest starts now! How excited it is to see balloons floating around. You, ...
- C类地址
C类地址第1字节.第2字节和第3个字节为网络地址,第4个字节为主机地址.另外第1个字节的前三位固定为110. C类地址范围:192.0.0.1到223.255.255.255.(第1个字节的二进制值前 ...
- jqeury之轮播图
$(document).ready(function(){ var sWidth = $('#pic1').width(); var len = $('#pic1 .sildebar li').len ...
- 关于viewport的研究
昨天项目中用到了适应移动端显示的viewport,一般的使用方式如下: <meta name="viewport" content="width=device-wi ...
- SqlSever基础 dateadd year,增加五年
镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...
- 可是把ie67下面的bug改好了,其实很简单,ie67下面取出来的字符串是带有空格的,不知道为什么
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- Writing Text File From A Tabular Block In Oracle Forms
The example given below for writing text file or CSV using Text_IO package from a tabular block in O ...
- Quick Trick About Using Dbms_Metadata With Forms_DDL In Oracle Forms
Example is given below to fetch any Oracle objects DDL script using DBMS_Metadata.Get_DDL command in ...
- 头文件为什么要加#ifndef #define #endif
#ifndef 在头文件中的作用 在一个大的软件工程里面,可能会有多个文件同时包含一个头文件,当这些文件编译链接成一个可执行文件时 ,就会出现大量“重定义”的错误.在头文件中实用#ifndef #de ...
- SQL语句最基本的性能优化方法
有些人还不知道sql语句的基本性能优化方法,在此我简单提醒一下,最基本的优化方法: 1.检查是否缺少索引.调试的时候开启“包括实际的执行计划” 执行后会显示缺少的索引, 然后让dba帮助添 ...