代码改变世界

读书笔记之 - javascript 设计模式 - 单体模式

2014-08-11 11:11  sai.zhao  阅读(213)  评论(0编辑  收藏  举报

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

单体模式,就是将代码组织为一个逻辑单元,这个逻辑单元中的代码可以通过单一的变量进行访问。

单体基本结构是这样:

var Singleton = {
    attribute1:true,
    attribute2:10,
    method1:function(){},
    method2:function(){}
}

借助闭包实现单体:

Namespace.Singleton = {}

定义之后立即执行的单体函数:

Namespace.Singleton = (function(){
    return {
        publicAttr:1,
        ...
};
})();

我们添加那层函数包装,就是为了使用包装函数来添加真正的私有成员的闭包。

闭包单体的实现方法:

GiantCorp.DataParser = (function(){
    var whitespaceRegex = /\s+/;
    function stripWhitespace(str){
        return str.replace(whitespaceRegex,'');
    };
    function stringSplit(str,delimiter){
        return str.split(delimiter);
    };
    return {
        stringToArray:function(str,delimiter,stripWS){
            if(stripWS){
                str = stripWhitespace(str);
            }
            var outputArray = stringSplit(str,delimiter);
            return outputArray;
        }
    }
})();

该函数中,这些私有方法和属性可以直接访问其名称,不必在前面加this。把私有成员放到闭包中可以确保其不会在单体对象之外被使用。同时可以自由的改变对象的实现细节。还可以用这种办法对数据进行保护和封装。

使用这种方式,你可以享受真正的私有成员带来的好处,而不必付出什么代价,这是因为单体类只会被实例化一次,单体模式之所以是javascript中最流行的,应用最广泛的的模式之一,原因即在此。

单体的惰性实例化

前面所讲的单体模式的实现有一个共同点:单体对象都是脚本加载的时候被创建出来的。

对于资源密集型的或配置开销甚大的单体,也许更合理的做法就是将其实例化推迟到需要使用的时候,这种技术被称为惰性加载。它最常用于那些必须加载大量数据的单体。

下面展示如何将普通单体转化为惰性加载单体:

MyNamespace.Singleton = (function(){
    var uniqueInstance;
    function constructor(){
      .....
    }
    return {
        getInstance:function(){
            if(!uniqueInstance){
                //没有实例化的情况下
                uniqueInstance = constructor();
            }
            return uniqueInstance;
        }
    }
})();
//调用
MyNamespace.Singleton.getInstance().publiceMethod1();

分支:分支是一种用来把浏览器之间的差异封装到在运行期间进行折中的动态处理的技术。

下面欣赏使用分支技术创建XHR对象:

var SimpleXhrFactory =(function(){
    var standard = {
        createXhrObject:function(){
            return new XMLHttpRequest();
        }
    };

    var activeNew = {
        createXhrObject:function(){
            return new ActiveXObject('Msxml2.XMLHTTP');
        }
    };

    var activeOld = {
        createXhrObject:function(){
            return new ActiveXObject('Microsoft.XMLHTTP');
        }
    };

    var testObject = null;
    try{
        testObject = standard.createXhrObject();
        return standard;
    }
    catch(e){
        try{
            testObject = activeNew.createXhrObject();
            return activeNew;
        }
        catch(e){
            try{
                testObject = activeOld.createXhrObject();
                return activeOld;
            }
            catch(e){
                throw new Error('No XHR object found in this environment.');
            }
        }
    }
})();

在大型项目中,单体可以起到优化的作用:那些开销大却又很少使用的组件可以被包装到惰性加载单体中;针对特点环境的代码则可以被包装到分支型单体中。