zoukankan      html  css  js  c++  java
  • 【转】对象创建模式

    原帖:http://www.douban.com/note/169097922/

    1. 命名空间模式

    // unsafe
    var MYAPP = {};
    // better
    if (typeof MYAPP === "undefined") {
        var MYAPP = {};
    }
    // or shorter
    var MYAPP = MYAPP || {};

    //一次性创建长命名层级时
    //确保每层都存在
    MYAPP.namespace = function (ns_string) {
        var parts = ns_string.split('.'),
            parent = MYAPP,
            i;
        // strip redundant leading global
        if (parts[0] === "MYAPP") {
            parts = parts.slice(1);
        }
        for (i = 0; i < parts.length; i += 1) {
            // create a property if it doesn't exist
            if (typeof parent[parts[i] === "undefined") {
                parent[parts[i] = {};
            }
            parent = parent[parts[i];
        }
        return parent;
    };

    // assign returned value to a local var
    var module2 = MYAPP.namespace('MYAPP.modules.module2');
    module2 === MYAPP.modules.module2; // true
    // skip initial `MYAPP`MYAPP.namespace('modules.module51');
    // long namespace
    MYAPP.namespace('once.upon.a.time.there.was.this.long.nested.property');


    2. 声明依赖 -----------------------------------------------------------------

    var myFunction = function () {
        // dependencies
        var event = YAHOO.util.Event,
            dom = YAHOO.util.Dom;
        // use event and dom variables
        // for the rest of the function...
    };

    function test2() {
        var modules = MYAPP.modules;
        alert(modules.m1);
        alert(modules.m2);
        alert(modules.m51);
    }

    优点:
    > 声明写在程序上部, 便于查找检查其依赖, 并确保相关模块文件的引入
    > 缓存成本地变量会比全局变量运行更快
    > 压缩工具会把本地变量替换成更短的名字


    3. 私有变量和方法 ----------------------------------------------------------

    3.1 在构造方法里用闭包创建私有成员:

    function Gadget() {
        // private member
        var name = 'iPod';
        // public function
        this.getName = function () {
            return name;
        };
    }

    *如果返回的是object或array, 因为传递的是引用, 数据可能被外部修改:
    function Gadget() {
        // private member
        var specs = {
            screen_ 320,
            screen_height: 480,
            color: "white"
        };
        // public function
        this.getSpecs = function () {
            return specs;
        };
    }
    解决的办法
    > 返回object或array等的clone对象
    > 用新方法, 比如getDimensions()等直接返回数值对象

    3.2 字面量对象实现隐私性:

    var myobj; // this will be the object
    (function () {
        // private members
        var name = "my, oh my";
        // implement the public part
        // note -- no `var`
        myobj = {
            // privileged method
            getName: function () {
                return name;
            }
        };
    }());



    var myobj = (function () {
        // private members
        var name = "my, oh my";
        // implement the public part
        return {
            getName: function () {
                return name;
            }
        };
    }());

    3.3 原型和隐私性:

    *使用构造函数创建隐私性会在每次都创建新对象, 从而耗费内存, 可以使用prototype解决

    function Gadget() {
        // private member
        var name = 'iPod';
        // public function
        this.getName = function () {
            return name;
        };
    }
    Gadget.prototype = (function () {
        // private member
        var browser = "Mobile Webkit";
        // public prototype members
        return {
            getBrowser: function () {
                return browser;
            }
        };
    }());

    3.4 揭秘模块模式

    *无法像ECMAScript5中的对象一样可以设置freeze属性使外界无法修改
     但是可以使用 revealing module pattern 暴露某些有必要保护的私有方法

    var myarray;
    (function () {
        var astr = "[object Array]",
            toString = Object.prototype.toString;
        function isArray(a) {
            return toString.call(a) === astr;
        }
        function indexOf(haystack, needle) {
            var i = 0,
                max = haystack.length;
            for (; i < max; i += 1) {
                if (haystack[i] === needle) {
                    return i;
                }
            }
            return 1;
        }
        myarray = {
            isArray: isArray,
            indexOf: indexOf,
            inArray: indexOf
        };
    }());
     
    即使外界修改了对象的indexOf, inArray引用的私有方法indexOf的功能依然正常

    myarray.indexOf = null;
    myarray.inArray(["a", "b", "z"], "z"); // 2


    4. 模块模式 ----------------------------------------------------------

    *广泛使用的模式, 提供结构化并帮助应付增长的代码, 在黑盒中实现增删改

    //首先定义命名空间
    MYAPP.namespace('MYAPP.utilities.array');
    //使用一个局部方法返回的对象创建模块, 从而实现私密性和公开的API
    MYAPP.utilities.array = (function () {
        // dependencies
        var uobj = MYAPP.utilities.object,
            ulang = MYAPP.utilities.lang,
            // private properties
            array_string = "[object Array]",
            ops = Object.prototype.toString;
            // private methods
            // ...
            // end var
        // optionally one-time init procedures
        // ...
        // public API
        return {
            inArray: function (needle, haystack) {
                for (var i = 0, max = haystack.length; i < max; i += 1) {
                    if (haystack[i] === needle) {
                        return true;
                    }
                }
            },
            isArray: function (a) {
                return ops.call(a) === array_string;
            }
            // ... more methods and properties
        };
    }());

    4.1 揭秘模块模式

    *结合使用模块和解密模式, 可以将所有方法设为私有, 并在局部方法的最后决定公开哪些API

    MYAPP.utilities.array = (function () {
        // private properties
        var array_string = "[object Array]",
            ops = Object.prototype.toString,
            // private methods
            inArray = function (haystack, needle) {
                for (var i = 0, max = haystack.length; i < max; i += 1) {
                    if (haystack[i] === needle) {
                        return i;
                    }
                }
                return −1;
            },
            isArray = function (a) {
                return ops.call(a) === array_string;
            };
            // end var
        // revealing public API
        return {
            isArray: isArray,
            indexOf: inArray
        };
    }());

    4.2 创建构造器的模块

    *某些情况下需要对象的构造器函数, 与上面例子的区别是返回一个function而非object

    MYAPP.namespace('MYAPP.utilities.Array');
    MYAPP.utilities.Array = (function () {
        // dependencies
        var uobj = MYAPP.utilities.object,
            ulang = MYAPP.utilities.lang,
            // private properties and methods...
            Constr;
            // end var
        // optionally one-time init procedures
        // ...
        // public API -- constructor
        Constr = function (o) {
            this.elements = this.toArray(o);
        };
        // public API -- prototype
        Constr.prototype = {
            constructor: MYAPP.utilities.Array,
            version: "2.0",
            toArray: function (obj) {
                for (var i = 0, a = [], len = obj.length; i < len; i += 1) {
                    a[i] = obj[i];
                }
                return a;
            }
        };
        // return the constructor to be assigned to the new namespace
        return Constr;
    }());

    var arr = new MYAPP.utilities.Array(obj);

    4.3 将全局变量传入模块

    *通常可以向局部方法中传递全局变量, 包括模块自身, 使其变为局部变量以加速

    MYAPP.utilities.module = (function (app, global) {
        // references to the global object
        // and to the global app namespace object
        // are now localized
    }(MYAPP, this));


    5. 沙盒模式 -------------------------------------------------------------------

    *此模式着眼于解决命名空间模式的以下缺陷:
     >一个页面中无法有两个以上的相同程序或库共存, 因为会共用全局的变量名
     >需要打印长的命名空间名称, 并在运行时解析之

    *沙盒模式使得模块在自己的沙盒中运行, 不受其他模块的影响

    //这个Sandbox可以命名成自己的程序名, 比如MYAPP
    function Sandbox() {
        var args = Array.prototype.slice.call(arguments), //将参数表转换为数组
            callback = args.pop(), //最后一个参数必须是callback方法
            //模块名称可以用数组或分开传递进来
            modules = (args[0] && typeof args[0] === "string") ? args : args[0],
            i;
        
        //确保方法由new操作符调用
        if (!(this instanceof Sandbox)) {
            return new Sandbox(modules, callback);
        }

        //一些必要的属性
        this.a = 1;
        this.b = 2;

        //将指定的模块附加到'this'对象上
        //没指定模块, 或者使用了'*', 将附加所有模块
        if (!modules || modules === '*') {
            modules = [];
            for (i in Sandbox.modules) {
                if (Sandbox.modules.hasOwnProperty(i)) {
                    modules.push(i);
                }
            }
        }
        //初始化所需模块
        for (i = 0; i < modules.length; i += 1) {
            Sandbox.modules[modules[i](this);
        }
        //调用callback, 其中使用的'this'就是附加了所需模块后的独立对象
        callback(this);
    }

    //一些必要的受保护信息
    Sandbox.prototype = {
        name: "My Application",
        version: "1.0",
        getName: function () {
            return this.name;
        }
    };

    //模块定义
    Sandbox.modules = {};
    Sandbox.modules.dom = function (box) {
        box.getElement = function () {};
        box.getStyle = function () {};
        box.foo = "bar";
    };
    Sandbox.modules.event = function (box) {
        // access to the Sandbox prototype if needed:
        // box.constructor.prototype.m = "mmm";
        box.attachEvent = function () {};
        box.dettachEvent = function () {};
    };
    Sandbox.modules.ajax = function (box) {
        box.makeRequest = function () {};
        box.getResponse = function () {};
    };

    //使用实例
    Sandbox(function (box) {
        //参数表中的box不写也行, 直接用this
    });
    Sandbox('*', function () {
        //等同于上一种
    });
    Sandbox(['ajax', 'event'], function (box) {
        // console.log(box);
    });
    Sandbox('ajax', 'dom', function (box) {
        // console.log(box);
    });
    Sandbox('dom', 'event', function (box) {
        // work with dom and event
        Sandbox('ajax', function (box) {
           // another sandboxed "box" object
           // this "box" is not the same as
           // the "box" outside this function
           //...
           // done with Ajax
        });
        // no trace of Ajax module here
    });

    http://www.nowamagic.net/javascript/js_SandBoxPatterm.php
    http://www.nowamagic.net/javascript/js_SandBox.php
    http://www.planabc.net/lab/yui/sandbox.html

    6. 静态成员 ---------------------------------------------------------------

    6.1 公开的静态成员

    // constructor
    var Gadget = function () {};
    // a static method
    Gadget.isShiny = function () {
        return "you bet";
    };
    // a normal method added to the prototype
    Gadget.prototype.setPrice = function (price) {
        this.price = price;
    };

    6.2 私有静态成员

    *所谓私有静态成员, 即只能在由构造函数创建的对象中共享的成员

    var Gadget = (function () {
        //静态变量/属性
        var counter = 0;
        // 返回的方法成为了新的构造函数
        return function () {
            console.log(counter += 1);
        };
    }()); //立即执行的局部方法

    var g1 = new Gadget(); // 1
    var g2 = new Gadget(); // 2
    var g3 = new Gadget(); // 3


    7. 对象常量 -------------------------------------------------------------

    *一般采用通行的全大写变量的方法表示常量, 如果确实需要不变的值, 可以这样:

    var constant = (function () {
        var constants = {},
            ownProp = Object.prototype.hasOwnProperty,
            allowed = {
                string: 1,
                number: 1,
                boolean: 1
            },
            prefix = (Math.random() + "_").slice(2);
        return {
            set: function (name, value) {
                if (this.isDefined(name)) {
                    return false;
                }
                if (!ownProp.call(allowed, typeof value)) {
                    return false;
                }
                constants[prefix + name] = value;
                return true;
            },
            isDefined: function (name) {
                return ownProp.call(constants, prefix + name);
            },
            get: function (name) {
                if (this.isDefined(name)) {
                    return constants[prefix + name];
                }
                return null;
            }
        };
    }());

    // check if defined
    constant.isDefined("maxwidth"); // false
    // define
    constant.set("maxwidth", 480); // true
    // check again
    constant.isDefined("maxwidth"); // true
    // attempt to redefine
    constant.set("maxwidth", 320); // false
    // is the value still intact?
    constant.get("maxwidth"); // 480


    8. 链式模式 -------------------------------------------------------------

    *就是jQuery式的调用方法:
     myobj.method1("hello").method2().method3("world").method4();

    如果方法没有明确的有意义的返回值时, 就可以返回this, 这样就可以实现链式模式
    var obj = {
        value: 1,
        increment: function () {
            this.value += 1;
            return this;
        },
        add: function (v) {
            this.value += v;
            return this;
        },
        shout: function () {
            alert(this.value);
        }
    };
    // chain method calls
    obj.increment().add(3).shout(); // 5
    // as opposed to calling them one by one
    obj.increment();
    obj.add(3);
    obj.shout(); // 5


    9. method()方法

    *使用prototype定义方法可能在写法上带来不便, 结合链式模式, 可以采用method()方法

    if (typeof Function.prototype.method !== "function") {
        Function.prototype.method = function (name, implementation) {
            this.prototype[name] = implementation;
            return this;
        };
    }

    var Person = function (name) {
        this.name = name;
    }.method('getName', function () {
        return this.name;
    }).method('setName', function (name) {
        this.name = name;
        return this;
    });

    var a = new Person('Adam');
    a.getName(); // 'Adam'
    a.setName('Eve').getName(); // 'Eve'

  • 相关阅读:
    kill -3 导出 thread dump
    JVM中锁优化,偏向锁、自旋锁、锁消除、锁膨胀
    Hibernate validator验证
    java子类实例初始化过程
    spring- properties 读取的五种方式
    Spring连接数据库的几种常用的方式
    缓存使用中的注意事项
    java动态代理原理
    classpath目录
    springmvc常用注解标签详解
  • 原文地址:https://www.cnblogs.com/missuu/p/3797139.html
Copyright © 2011-2022 走看看