zoukankan      html  css  js  c++  java
  • Javascript OOP框架YOOP重构实践(下) Wonder

    继续重构

    提取基类Structure

    增加测试

    describe("测试AClass", function () {
        it("子类全部实现抽象父类的抽象成员时,不抛出异常", function () {
            var A = YYC.AClass({
                Init: function (t) {
                    this.a = t;
                    this.b = 2;
                },
                Public: {
                    p: function () {
                        return 0;
                    }
                },
                Private: {
                    _m: 1
                },
                Protected: {
                    P_h: function () {
                        return this._m;
                    },
                    P_k: 3
                },
                Abstract: {
                    move: function () { },
                    u: 0,
                    t: function () { }
                }
            });
            var B = YYC.Class(A, {
                Init: function () {
                    this.b = 100;
                    this.base(200);
                },
                Public: {
                    move: function () {
                        return this.P_h();
                    },
                    t: function () { },
                    u: 20
                }
            });
            var C = YYC.Class(B, {
                Public: {
                    move: function () {
                        var baseResult = this.base();
    
                        return baseResult;
                    },
                    t: function () { }
                }
            });
    
            var b = new B();
            var c = new C();
    
            expect([b.a, b.b]).toEqual([200, 2]);
            expect([b.p(), b.move(), b.u]).toEqual([0, 1, 20]);
            expect(c.move()).toEqual(1);
        });
    });
    
    describe("测试Interface", function () {
        it("子类没有全部实现了接口方法和属性,抛出异常", function () {
            var Int = YYC.Interface("A", "B");
    
            expect(function () {
                YYC.AClass({ Interface: Int }, {
                    Public: {
                        B: function () { }
                    }
                });
            }).toThrow();
    
            var Int2 = YYC.Interface(Int, ["C"], ["a"]);
    
            expect(function () {
                YYC.AClass({ Interface: Int2 }, {
                    Public: {
                        A: function () { },
                        B: function () { },
                        C: function () { }
                    }
                });
            }).toThrow();
            expect(function () {
                YYC.AClass({ Interface: Int2 }, {
                    Public: {
                        B: function () { },
                        C: function () { },
                        a: 1
                    }
                });
            }).toThrow();
        });
    });
    View Code

    通过重构实践(一)的重构,我发现AClass和Class有很多相似之处,因此启发我采用oo思想来重构,提取出AClass和Class的基类Structure,将两者的共同或相似的代码放到Structure中,然后在Structure中运用模板模式,调用子类实现的方法或属性(如P_class、P_prepareCheck)。

    另外进行上面的重构后,可以减少一些方法的形参个数,因为这些形参可以在方法内部通过this来获得了。

    如_addStatic重构前:

    function _addStatic(_class, prop) {
        var Static = null;
        var k = null;
    
        Static = prop.Static ? prop.Static : null;
        //静态属性/方法赋值
        for (k in Static) {
            _class[k] = Static[k];
        }
    };

    重构后(_addStatic移到Structure中,并改名为P_addStatic,表示为保护方法):

    this.P_addStatic = function () {
        var Static = null,
            k = null,
            _class = this.P_class,
            prop = this.prop;
    
        Static = prop.Static ? prop.Static : null;
        //静态属性/方法赋值
        for (k in Static) {
            _class[k] = Static[k];
        }
    };

    然后又进行了一些小的重构(如删除密封方法的判断、检查;将AClass、Class中调用成员的职责提取为buildAClass、buildClass;重命名addPublic为prepareAndAddPublic等),重构后结构A2(包括Structure、AClass、Class)为:

    (function () {
    
        function Structure() {
            this.parentClass = null;
            this.interface = null;
            this.prop = null;
    
            /* 深拷贝
        */
            this.P_extendDeep = function (parent, child) {
                var i = null,
                len = 0,
                      toStr = Object.prototype.toString,
                      sArr = "[object Array]",
                      sOb = "[object Object]",
                      type = "",
               _child = null;
    
                //数组的话,不获得Array原型上的成员。
                if (toStr.call(parent) === sArr) {
                    _child = child || [];
    
                    for (i = 0, len = parent.length; i < len; i++) {
                        type = toStr.call(parent[i]);
                        if (type === sArr || type === sOb) {    //如果为数组或object对象
                            _child[i] = type === sArr ? [] : {};
                            arguments.callee(parent[i], _child[i]);
                        } else {
                            _child[i] = parent[i];
                        }
                    }
                }
                    //对象的话,要获得原型链上的成员。因为考虑以下情景:
                    //类A继承于类B,现在想要拷贝类A的实例a的成员(包括从类B继承来的成员),那么就需要获得原型链上的成员。
                else if (toStr.call(parent) === sOb) {
                    _child = child || {};
    
                    for (i in parent) {
                        type = toStr.call(parent[i]);
                        if (type === sArr || type === sOb) {
                            _child[i] = type === sArr ? [] : {};
                            arguments.callee(parent[i], _child[i]);
                        } else {
                            _child[i] = parent[i];
                        }
                    }
                }
                else {
                    _child = parent;
                }
    
    
                return _child;
            };
            //检查子类的公有方法+虚方法+抽象方法是否包含父类的抽象方法/属性 或 接口方法/属性。
            //不用hasOwnProperty判断!否则就检查不到是否包含了父类的抽象方法/属性 或 接口方法/属性。
            this.P_check = function (parentClass) {
                //var parentClass = this.parentClass,
                var interface = this.interface,
                    children = this.children;
    
                if (parentClass) {
                    _checkAbstract(parentClass, children);
                }
                else if (interface) {
                    _checkInterface(interface, children);
                }
            };
            function _checkAbstract(parentClass, children) {
                var name = "";
    
                //检查是否实现了抽象方法/属性
                for (name in parentClass.prototype) {
                    if (parentClass.prototype.hasOwnProperty(name)) {
                        if (name === "constructor") {
                            continue;
                        }
                        if (name.contain("Abstract_")) {
                            //抽象方法
                            if (typeof parentClass.prototype[name] === "function") {
                                if (_noMethodForAbstract(children, name) && _noMethodForAbstract(parentClass.prototype, name)) {
                                    throw new Error("Abstract method '" + name + "' must be overwrited!");
                                }
                            }
                                //抽象属性
                            else {
                                if (_noAttritubeForAbstract(children, name) && _noAttritubeForAbstract(parentClass.prototype, name)) {
                                    throw new Error("Abstract attribute '" + name + "' must be overwrited!");
                                }
                            }
                        }
                    }
                }
            };
            function _checkInterface(interface, children) {
                var name = "";
    
                //检查是否实现了接口方法/属性
                for (name in interface.prototype) {
                    if (name === "constructor") {
                        continue;
                    }
                    //接口方法
                    if (typeof interface.prototype[name] === "function") {
                        if (_noMethodForInterface(children, name) && _noMethodForInterface(parentClass.prototype, name)) {
                            throw new Error("Interface method '" + name + "' must be overwrited!");
                        }
                    }
                        //接口属性
                    else {
                        if (_noAttritubeForInterface(children, name) && _noAttritubeForInterface(parentClass.prototype, name)) {
                            throw new Error("Interface attribute '" + name + "' must be overwrited!");
                        }
                    }
                }
            };
    
            function _noMethodForAbstract(_class, name) {
                return _class[name.slice(9)] === undefined || typeof _class[name.slice(9)] !== "function";
            };
            function _noAttritubeForAbstract(_class, name) {
                return _class[name.slice(9)] === undefined || typeof _class[name.slice(9)] === "function";
            };
            function _noMethodForInterface(_class, name) {
                return _class[name.slice(10)] === undefined || typeof _class[name.slice(10)] !== "function";
            };
            function _noAttritubeForInterface(_class, name) {
                return _class[name.slice(10)] === undefined || typeof _class[name.slice(10)] === "function";
            };
    
            //检查抽象成员
            this.P_addAbstract = function (abstract) {
                var name = "",
                    currentClass = this.P_class;
    
                for (name in abstract) {
                    if (abstract.hasOwnProperty(name)) {
                        //抽象方法前面加"Abstract_"前缀
                        currentClass.prototype["Abstract_" + name] = abstract[name];
                        //temp[name] = abstract[name];    //加入temp
                    }
                }
            };
    
            //检查虚方法(不能为虚属性)
            this.P_addVirtual = function (virtual) {
                var name = "",
                    currentClass = this.P_class;
    
                for (name in virtual) {
                    if (virtual.hasOwnProperty(name)) {
                        if (typeof virtual[name] !== "function") {
                            throw new Error("Virtual attribute is not allowed!");
                        }
                        else {
                            currentClass.prototype[name] = virtual[name];
                            //temp[name] = virtual[name];    //加入this.temp
                        }
                    }
                }
            };
    
            ////加入密封方法。
            ////没有实现检查子类是否重写了父类的密封方法,只是定义了一个规范。
            //this.P_addSealed = function (sealed, currentClass) {
            //    var name = "";
    
            //    for (name in sealed) {
            //        if (sealed.hasOwnProperty(name)) {
            //            currentClass.prototype[name] = sealed[name];
            //            //temp[name] = sealed[name];    //加入this.temp
            //        }
            //    }
            //};
    
            //获得在原型prototype中不存在同名的str。
            //如果有同名,则加上前缀"_"
            this.P_getNoRepeatStrInPrototype = function (prototype, str) {
                var new_str = "";
    
                if (!prototype[str]) {
                    return str;
                }
                new_str = "_" + str;
    
                return arguments.callee(prototype, new_str);
            };
            this.P_addStatic = function () {
                var Static = null,
                    k = null,
                    _class = this.P_class,
                    prop = this.prop;
    
                Static = prop.Static ? prop.Static : null;
                //静态属性/方法赋值
                for (k in Static) {
                    _class[k] = Static[k];
                }
            };
    
            this.P_inherit = function () {
                var _class = this.P_class,
                    parentClass = this.parentClass;
    
                _class.prototype = this.P_extendDeep(parentClass.prototype);
                _class.prototype.constructor = _class;
    
                // 如果父类存在,则实例对象的baseClass指向父类的原型。
                // 这就提供了在实例对象中调用父类方法的途径。
                //baseClass的方法是指向this.parentClass的,不是指向F(子类)的!
                _class.prototype[this.P_getNoRepeatStrInPrototype(parentClass.prototype, "baseClass")] = parentClass.prototype;
            };
            this.P_addInit = function () {
                //var self = this;
                var _class = this.P_class,
                    parentClass = this.parentClass,
                    prop = this.prop;
    
                if (prop.Init) {
                    // 如果此类继承自父类this.parent并且父类原型中存在同名函数name
                    if (parentClass &&
            typeof prop.Init === "function" &&
            typeof _class.prototype.Init === "function") {
                        //if (this.parentClass) {
                        _class.prototype.Init = function (name) {
                            return function () {
                                /*
                                //此处不用创建闭包了!因为外面已经创建了闭包,name已经被保存了!
                                this.baseToParrent = function () {
                                    //这个写法也可以!为什么不用apply修正this也行??!
                                    //this.parentClass.prototype[name](); 
            
                                    //此处的arguments为baseToParrent方法传入的形参
                                    //注意!要加上“return”,这样才能返回this.parentClass.prototype[name]的返回值
                                    return this.parentClass.prototype[name].apply(this.parentClass.prototype, arguments);
                                };
                                */
                                //指向子类,可以用于模版模式
                                this.base = parentClass.prototype[name];
    
                                //执行fn并返回执行的结果
                                //此处的arguments为F.prototype[name]方法传入的形参。
                                return prop[name].apply(this, arguments);
                            };
    
                        }("Init");
                    }
                    else {
                        _class.prototype.Init = prop.Init;
                    }
                }
            };
    
            this.P_addPrivate = function () {
                var name = null,
                    _class = this.P_class,
                    private = this.prop.Private;
    
                if (private) {
                    //私有属性/方法直接覆盖
                    for (name in private) {
                        if (private.hasOwnProperty(name)) {
                            _class.prototype[name] = private[name];
                        }
                    }
                }
            };
    
            this.P_prepareAndAddPublic = function () {
                var name = null;
    
                if (this.prop.Public) {
                    for (name in this.prop.Public) {
                        if (this.prop.Public.hasOwnProperty(name)) {
                            if (this.P_prepareCheck("Public", name) === "continue") {
                                continue;
                            }
                            this.P_addPublic(name);
                            this.children[name] = this.prop.Public[name];
                        }
                    }
                }
            };
    
            this.P_addPublic = function (name) {
                var self = this;
    
                if (this.parentClass &&
                    typeof this.prop.Public[name] === "function" &&
                    typeof this.P_class.prototype[name] === "function") {
                    this.P_class.prototype[name] = function (name) {
                        return function () {
                            /*
                            //此处不用创建闭包了!因为外面已经创建了闭包,name已经被保存了!
                            self.baseToParrent = function () {
                                //这个写法也可以!为什么不用apply修正this也行??!
                                //this.parentClass.prototype[name](); 
        
                                //此处的arguments为baseToParrent方法传入的形参
                                //注意!要加上“return”,这样才能返回self.parentClass.prototype[name]的返回值
                                return self.parentClass.prototype[name].apply(self.parentClass.prototype, arguments);
                            };
                            */
                            //指向子类,可以用于模版模式
                            this.base = self.parentClass.prototype[name];
    
                            //执行fn并返回执行的结果
                            //此处的arguments为F.prototype[name]方法传入的形参。
                            return self.prop.Public[name].apply(this, arguments);
                        };
    
                    }(name);
                }
                else {
                    this.P_class.prototype[name] = this.prop.Public[name];
                }
            };
    
            this.P_prepareAndAddProtected = function () {
                var name = null;
    
                if (this.prop.Protected) {
                    for (name in this.prop.Protected) {
                        if (this.prop.Protected.hasOwnProperty(name)) {
                            if (this.P_prepareCheck("Protected", name) === "continue") {
                                continue;
                            }
                            this.P_class.prototype[name] = this.prop.Protected[name];
                            this.children[name] = this.prop.Protected[name];
                        }
                    }
                }
            };
        };
    
    
        //创建抽象类
        //抽象类能够继承接口、抽象类以及实体类,但此处约定抽象类只能继承接口和抽象类,不能继承实体类!
        //(这样方便判断抽象类是否包含全部的父类(接口/抽象类)成员)
    
        function AClass() {
            var that = this;
    
            this.children = {};
            this.P_class = A;
    
            // 本次调用所创建的类(构造函数)
            function A() {
            }
    
            var _getByParent = function (_parent, _prop) {
                //if (arguments.length === 1) {
                if (_prop === undefined) {
                    that.prop = _parent;
                    that.parentClass = null;
                    that.interface = null;
                }
                else if (typeof _parent === "object") {
    
                    if (!_parent.Class && !_parent.Interface) {
                        throw new Error("Please add AbstractClass or Interface!");
                    }
                    if (_getFunctionName(_parent.Class) === "F" || _getFunctionName(_parent.Interface) === "F") {
                        throw new Error("AbstractClass here can't inherit this.parentClass which is created by Class function!");
                    }
    
                    that.parentClass = _parent.Class;
                    that.interface = _parent.Interface;
                    that.prop = _prop;
                }
                    //_parent直接为xx,就表示父类为抽象类
                else if (typeof _parent === "function") {
                    if (_getFunctionName(_parent) === "F") {
                        throw new Error("AbstractClass here can't inherit this.parentClass which is created by Class function!");
                    }
    
                    that.parentClass = _parent;
                    that.interface = null;
                    that.prop = _prop;
                }
                else {
                    throw new Error("arguments is not allowed!");
                }
            };
            this.P_prepareCheck = function (where, name) {
                //检查抽象成员,抽象成员放到Public或Protected中
                if (name === "Abstract") {
                    //this.P_addAbstract(this.prop[where][name], A, this.children);
                    this.P_addAbstract(this.prop[where][name]);
                    return "continue";
                }
                //检查虚方法,虚方法放到Public或Protected中
                if (name === "Virtual") {
                    this.P_addVirtual(this.prop[where][name]);
                    return "continue";
                }
            };
            this.buildAClass = function (_parent, _prop) {
                //取出父类、接口
                _getByParent(_parent, _prop);
    
                // 如果此接口需要从其它接口扩展
                if (this.parentClass) {
                    this.P_inherit();
                }
    
                //加入构造函数
                //抽象类本身因为不能实例化,所以不调用构造函数。
                //抽象类中的构造函数供子类构造函数中调用。
                this.P_addInit();
    
                this.P_addPrivate();
    
                this.P_prepareAndAddPublic();
    
    
                //保护成员
                //_prepareAndAddProtected();
                this.P_prepareAndAddProtected();
    
                //放到外面的抽象成员,默认为公有抽象成员
                this.P_addAbstract(this.prop.Abstract);
    
                this.P_addStatic();
    
                //检查抽象类的公有方法+虚方法+抽象方法是否包含父类的接口方法/属性
                this.P_check(null);
    
                return A;
            };
    
        };
    
    
        AClass.prototype = new Structure();
    
        //创建普通类
        //父类_parent可以为{Class: xx, Interface: xx},或者直接为xx类
        function Class() {
            var that = this;
    
            this.P_class = F;
            this.children = {};
            //当前是否处于创建类的阶段。
            this.initializing = false;
            //原型恢复标志,用于防止第一次创建实例时恢复原型
            this.mark_resume = false;
    
            // 本次调用所创建的类(构造函数)
            function F() {
                //防止第一次创建实例时恢复原型
                if (that.mark_resume) {
                    //还原原型
                    that.P_extendDeep(F.backUp_prototype, F.prototype);
                }
                else {
                    that.mark_resume = true;
                }
    
                // 如果当前处于实例化类的阶段,则调用Init原型函数
                if (!that.initializing) {
                    this.Init && this.Init.apply(this, arguments);
                }
                /*不能删除私有成员和保护成员!否则类的成员就不能调用到私有和保护的成员了(因为已经删除了)!
                对象的创建算法参考http://www.cnblogs.com/TomXu/archive/2012/02/06/2330609.html
            
            
            
            
                //删除私有成员和保护成员,这样外界就不能访问私有和保护成员了!
                for (name in this) {
                if (name.search(/(^_)|(^P_)/) !== -1) {
                delete F.prototype[name];
                //                                                    this[name] = null;
                }
                  
                }
                */
            }
    
            var _getByParent = function (_parent, _prop) {
                //if (arguments.length === 1) {
                if (_prop === undefined) {
                    that.prop = _parent;
                    that.parentClass = null;
                    that.interface = null;
                }
                    //{Class: xx, Interface: xx}
                else if (typeof _parent === "object") {
                    if (!_parent.Class && !_parent.Interface) {
                        throw new Error("Please add Class or Interface!");
                    }
    
                    that.parentClass = _parent.Class;
                    that.interface = _parent.Interface;
                    that.prop = _prop;
                }
                    //直接为xx类
                else if (typeof _parent === "function") {
                    that.parentClass = _parent;
                    that.interface = null;
                    that.prop = _prop;
                }
                else {
                    throw new Error("arguments is not allowed!");
                }
            };
            //this._addParentSealed = function () {
            //    var name = null;
    
            //    for (name in this.parentClass.prototype) {
            //        if (this.parentClass.prototype.hasOwnProperty(name)) {
            //            //如果不是抽象方法/保护方法/私有方法/接口成员,则加入到this.temp中。
            //            //用于添加父类的密封方法(因为子类并没有加入父类的密封方法)。
            //            if (!name.match(/^Abstract_/) || !name.match(/^P_/) || !name.match(/^_/) || !name.match(/^Interface_/)) {
            //                this.children[name] = this.parentClass.prototype[name];
            //            }
            //        }
            //    }
            //};
            this.P_prepareCheck = function (where, name) {
                //检查虚方法,虚方法放到Public或Protected中
                if (name === "Virtual") {
                    this.P_addVirtual(this.prop[where][name]);
                    return "continue";
                }
                ////密封的方法(不允许子类重写)
                //if (name === "Sealed") {
                //    this.P_addSealed(this.prop[where][name], A);
                //    return "continue";
                //}
    
                return null;
            };
    
            this.buildClass = function (_parent, _prop) {
                _getByParent(_parent, _prop);
    
                // 如果此类需要从其它类扩展
                if (this.parentClass) {
                    this.initializing = true;
                    this.P_inherit();
                    this.initializing = false;
                }
    
                this.P_addInit();
    
                this.P_addPrivate();
    
                //保护成员
                this.P_prepareAndAddProtected();
    
                if (this.prop.Abstract) {
                    throw new Error("Only abstractClass can have abstract methods!");
                }
                this.P_prepareAndAddPublic();
    
                //检查公有成员和虚函数是否实现了抽象方法/属性 或 接口方法/属性
                this.P_check();
    
                this.P_addStatic();
    
                //备份原型
                F.backUp_prototype = this.P_extendDeep(F.prototype);
    
                return F;
            };
        };
    
        Class.prototype = new Structure();
    
        /*
        下面的写法有问题!因为只有载入oopFrame.js时,创建了AClass的实例。
        调用YYC.AClass时,只是引用该实例的buildAClass,而不会再创建AClass实例。
        也就是说,所有YYC.AClass都共用一个AClass的实例!共用AClass实例的属性(如parent等)!
    
        YYC.AClass = new AClass().buildAClass;
        */
    
    
        YYC.AClass = function (_parent, _prop) {
            return new AClass().buildAClass(_parent, _prop);
        };
        YYC.Class = function (_parent, _prop) {
            return new Class().buildClass(_parent, _prop);
        };
    }());
    View Code

    重构Interface

    去掉i、args变量,提取出buildInterface方法,用oo思想重构Interface:

    function Interface() {
        var that = this;
    
        this.parent = null;
        this.method = null;
        this.attribute = null;
    
        function I() {
        }
    
        function _getByParent(_parent, _method, _attribute) {
            if (typeof _parent === "function") {
                if (_getFunctionName(_parent) !== "I") {
                    throw new Error("Interface must inherit interface!");
                }
                else {
                    that.parent = _parent;
                    //形如“Interface(Parent, "A", "B", "GetName");”
                    if (_method && !_isArray(_method)) {
                        that.method = Array.prototype.slice.call(arguments, 1);
                        that.attribute = null;
                    }
                        //形如“Interface(Parent, ["A", "B", "GetName"], ["a", "c"]);”
                    else {
                        that.method = _method;
                        that.attribute = _attribute;
                    }
                }
            }
            else {
                that.parent = null;
                //形如“Interface("A", "B", "GetName");”
                if (_method && !_isArray(_method)) {
                    that.method = Array.prototype.slice.call(arguments, 0);
                    that.attribute = null;
                }
                    //形如“Interface(["A", "B", "GetName"], ["a", "c"]);”
                else {
                    that.method = arguments[0];
                    that.attribute = arguments[1];
                }
            }
        };
        function _inherit() {
            I.prototype = new that.parent();
            I.prototype.constructor = I;
        };
        function _addMethod() {
            var i = 0,
                len = 0;
    
            for (i = 0, len = that.method.length; i < len; i++) {
                //加上前缀“Interface_”
                I.prototype["Interface_" + that.method[i]] = function () {
                    throw new Error("This method must be overwrited!");
                };
            }
        };
        function _addAttribute() {
            var i = 0,
                len = 0;
    
            if (that.attribute) {
                if (!_isArray(that.attribute)) {
                    throw new Error("Attribute must be array!");
                }
                else {
                    for (i = 0, len = that.method.length; i < len; i++) {
                        //加上前缀“Interface_”
                        I.prototype["Interface_" + that.attribute[i]] = 0;
                    }
                }
            }
        };
    
        this.buildInterface = function (_parent, _method, _attribute) {
            _getByParent(_parent, _method, _attribute);
            // 如果此接口需要从其它接口扩展
            if (this.parent) {
                _inherit();
            }
            //方法
            _addMethod();
            //属性
            _addAttribute();
    
            return I;
        };
    };
    View Code

    增加测试

    增加测试"子类虚方法实现抽象父类的抽象方法时,不抛出异常"、"非抽象类定义抽象成员时抛出异常":

    it("子类虚方法实现抽象父类的抽象方法时,不抛出异常", function () {
        var A = YYC.AClass({
            Abstract: {
                move: function () { }
            }
        });
        expect(function () {
            YYC.Class(A, {
                Public: {
                    Virtual: {
                        move: function () { }
                    }
                }
            });
        }).not.toThrow();
    });
    it("非抽象类定义抽象成员时抛出异常", function () {
        expect(function () {
            YYC.Class({
                Protected: {
                    Abstract: {
                        move: function () { }
                    }
                }
            });
        }).toThrow();
        expect(function () {
            YYC.Class({
                Abstract: {
                    move: function () { }
                }
            });
        }).toThrow();
    });
    View Code

    重构children

    之前将temp改名为children,但是现在发现这个名字也不恰当,因此根据它的职责“存储该类成员的名称,从而用于检查该类成员是否实现了接口或者父类的抽象成员。”,将其改名为impletationMap。

    将“存储该类成员的名称”的操作封装为函数P_addToImplementMap,放到Structure中:

    this.P_addToImplementMap = function (name, func) {
        this.implementaionMap[name] = func;
    };

    然后又经过了下面的重构

    • 将Structure -> P_prepareAndAddProtected、P_prepareAndAddPublic、P_addVirtual中“将实现方法加入到ImpletationMap中”的职责提取出来形成P_prepareCheck方法,并将原方法改名为P_addPublicMember、P_addProtectedMember。
    • 将Structure ->P_addPrivate、P_addStatic改名为P_addPrivateMember、P_addStaticMember。
    • 将buildClass、buildAClass中的加入外部的抽象成员职责提取为_addOuterAbstract方法。
    • 将Class -> F中恢复F.prototype和初始化职责分别提取为_restorePrototype、_init方法。
    • 将Structure的实例属性下移到子类中。

    性能优化

    为了优化性能,减少占用的内存,考虑将Interface、Structure、AClass、Class的实例成员改写成原型成员。

    重构Struture后,Structure的结构为:

    function Structure() {
    };
    Structure.prototype = (function () {}());

    当我将AClass改写成原型形式后,发现测试不能通过,原来是如果写成原型形式,则AClass的实例就共享同一个内部函数A!这样会造成不同的类之间互相干扰!

    因此,没有对Interface、AClass、Class进行该重构。

    改变原有的行为

    我需要增加“支持继承多个接口”,因此我先添加了测试用例,然后实现。另外我需要增加“限制只能最多继承一个类”,因此我也先添加测试用例,然后加入限制。

    在改变代码原有行为时,可能需要改变或增加相应的测试用例。那么不用迟疑,立刻就去做。

    重构注释

    删除不必要的注释,添加重要的算法说明、重构说明等注释。

    尽量少些注释,通过对类、函数、属性等的命名来体现职责和目的。

    以下来自《代码整洁之道》,可作为参考:
    好注释:法律信息,提供信息的注释,对意图的解释,阐释,警示,TODO注释,放大,共用API中的javadoc
    坏注释:喃喃自语,多余的注释,误导性的注释,循规式的注释,日志式注释,废话注释,可怕的废话,能用函数或变量时就别用注释,位置标记,括号后面的注释,归属与署名,注释掉的代码,函数头,非共用API中的javadoc。

    完成重构

    最终的测试代码:

    describe("YOOP", function () {
        it("不存在虚属性的概念(如果企图声明虚属性,会抛出异常)", function () {
            expect(function () {
                YYC.Class({
                    Virtual: {
                        a: ""
                    }
                });
            }).toThrow();
            expect(function () {
                YYC.AClass({
                    Virtual: {
                        a: ""
                    }
                });
            }).toThrow();
        });
        it("静态方法的this是指向类的", function () {
            var A = YYC.Class({
                Static: {
                    a: 100,
                    method: function () {
                        this.b = 300;
                        return 200;
                    }
                }
            });
            var result = A.method();
    
            expect(result).toEqual(200);
            expect(A.b).toEqual(300);    //300
        });
    
        describe("测试Class与AClass", function () {
            function testInheritFromOnlyOneClass(_class) {
                var A = YYC.AClass({});
                var B = YYC.AClass({});
    
                expect(function () {
                    YYC[_class](A, B, {});
                }).toThrow();
                expect(function () {
                    YYC[_class]({ Class: [A, B] }, {});
                }).toThrow();
            };
    
            describe("测试类Class", function () {
                it("可以继承多个接口。如果不实现会抛出异常", function () {
                    var A = YYC.Interface("m1");
                    var B = YYC.Interface("m2");
    
                    expect(function () {
                        YYC.Class({ Interface: A }, {
                            Public: {
                            }
                        });
                    }).toThrow();
                    expect(function () {
                        YYC.Class({ Interface: [A] }, {
                            Public: {
                            }
                        });
                    }).toThrow();
    
                    expect(function () {
                        YYC.Class({ Interface: [A, B] }, {
                            Public: {
                                m1: function () { }
                            }
                        });
                    }).toThrow();
                    expect(function () {
                        YYC.Class({ Interface: [A, B] }, {
                            Public: {
                                m2: function () { }
                            }
                        });
                    }).toThrow();
                    expect(function () {
                        YYC.Class({ Interface: [A, B] }, {
                            Public: {
                                m1: function () { },
                                m2: function () { }
                            }
                        });
                    }).not.toThrow();
                });
    
                it("只能继承一个类(Class或AClass),否则抛出异常", function () {
                    testInheritFromOnlyOneClass("Class");
                });
                it("创建实例时调用构造函数", function () {
                    var A = YYC.Class({
                        Init: function () {
                            this.a = 10;
                        }
                    });
    
                    expect(new A().a).toEqual(10);
                });
    
                describe("获得公有成员", function () {
                    it("如果父类不存在,能够正确获得公有方法", function () {
                        var Class = YYC.Class({
                            Public: {
                                a: function () {
                                    this.b = 1;
                                    return 0;
                                }
                            }
                        });
    
                        var cla = new Class();
                        var result = cla.a();
    
                        expect(result).toEqual(0);
                        expect(cla.b).toEqual(1);
                    });
                });
                it("不能定义抽象成员,否则抛出异常", function () {
                    expect(function () {
                        YYC.Class({
                            Public: {
                                Abstract: {
                                    move: function () { }
                                }
                            }
                        })
                    }).toThrow();
                });
                it("可以将虚方法定义在外面,表示公有虚方法", function () {
                    var A = YYC.Class({
                        Virtual: {
                            move: function () { }
                        }
                    });
    
                    expect(function () {
                        new A().move()
                    }).not.toThrow();
                });
                it("验证是否实现了接口成员,如果没有实现会抛出异常", function () {
                    var I = YYC.Interface(["move"], ["a"]);
    
                    expect(function () {
                        YYC.Class({ Interface: I }, {
                            Public: {
                                a: 0
                            }
                        });
                    }).toThrow();
                    expect(function () {
                        YYC.Class({ Interface: I }, {
                            Public: {
                                move: function () { }
                            }
                        });
                    }).toThrow();
                    expect(function () {
                        YYC.Class({ Interface: I }, {
                            Public: {
                                a: 0,
                                move: function () { }
                            }
                        });
                    }).not.toThrow();
                });
                it("验证是否实现了父类抽象成员,如果没有实现会抛出异常", function () {
                    var A = YYC.AClass({
                        Abstract: {
                            move: function () { },
                            a: 0
                        }
                    });
    
                    expect(function () {
                        YYC.Class(A, {
                            Public: {
                                a: 0
                            }
                        });
                    }).toThrow();
                    expect(function () {
                        YYC.Class(A, {
                            Public: {
                                move: function () { }
                            }
                        });
                    }).toThrow();
                    expect(function () {
                        YYC.Class(A, {
                            Public: {
                                a: 0,
                                move: function () { }
                            }
                        });
                    }).not.toThrow();
                });
            });
    
            describe("测试抽象类AClass", function () {
                it("可以继承多个接口(在抽象类中不用实现,可以交给子类Class实现)", function () {
                    var A = YYC.Interface("m1");
                    var B = YYC.Interface(["m2"], ["a"]);
                    var C = YYC.AClass({ Interface: [A, B] }, {});
    
                    expect(function () {
                        YYC.Class(C, {
                            Public: {
                                m1: function () { }
                            }
                        });
                    }).toThrow();
                    expect(function () {
                        YYC.Class(C, {
                            Public: {
                                m2: function () { }
                            }
                        });
                    }).toThrow();
                    expect(function () {
                        YYC.Class(C, {
                            Public: {
                                m1: function () { },
                                m2: function () { }
                            }
                        });
                    }).toThrow();
                    expect(function () {
                        YYC.Class(C, {
                            Public: {
                                m1: function () { },
                                m2: function () { },
                                a: 1
                            }
                        });
                    }).not.toThrow();
                });
                it("只能继承一个类(Class或AClass),否则抛出异常", function () {
                    testInheritFromOnlyOneClass("AClass");
                });
                it("构造函数供子类调用", function () {
                    var A = YYC.AClass({
                        Init: function () {
                            throw new Error();
                        }
                    });
                    var B = YYC.Class(A, {
                        Init: function () {
                            this.a = 10;
                        }
                    });
                    var C = YYC.Class(A, {
                        Init: function () {
                            this.a = 10;
                            this.base();
                        }
                    });
    
                    expect(function () {
                        new B();
                    }).not.toThrow();
                    expect(function () {
                        new C();
                    }).toThrow();
    
                });
                it("抽象类如果继承实体类,会抛出异常", function () {
                    var A = YYC.Class({});
                    expect(function () {
                        YYC.AClass(A, {});
                    }).toThrow();
                });
                it("子类虚方法实现抽象父类的抽象方法时,不抛出异常", function () {
                    var A = YYC.AClass({
                        Abstract: {
                            move: function () { }
                        }
                    });
                    expect(function () {
                        YYC.Class(A, {
                            Public: {
                                Virtual: {
                                    move: function () { }
                                }
                            }
                        });
                    }).not.toThrow();
    
                    expect(function () {
                        YYC.Class(A, {
                            Public: {
                            }
                        });
                    }).toThrow();
                });
                it("可以将虚方法定义在外面,表示公有虚方法", function () {
                    var A = YYC.AClass({
                        Virtual: {
                            move: function () { }
                        }
                    });
                    var B = YYC.Class(A, {});
    
                    expect(function () {
                        new B().move()
                    }).not.toThrow();
                });
                it("可以将抽象成员定义在外面,表示公有抽象成员", function () {
                    var A = YYC.AClass({
                        Abstract: {
                            move: function () { }
                        }
                    });
    
                    expect(function () {
                        YYC.Class(A, {
                            Public: {
                                move: function () { }
                            }
                        });
                    }).not.toThrow();
                });
                it("不验证是否实现父类的抽象成员(可以交给子类Class实现)", function () {
                    var A = YYC.AClass({
                        Abstract: {
                            move: function () { },
                            a: 0
                        }
                    });
                    var B = YYC.AClass(A, {});
                    var C = YYC.AClass(B, {});
    
                    expect(function () {
                        YYC.AClass(A, {
                            Public: {
                                a: 0
                            }
                        });
                    }).not.toThrow();
                    expect(function () {
                        YYC.AClass(A, {
                            Public: {
                                move: function () { }
                            }
                        });
                    }).not.toThrow();
    
    
                    expect(function () {
                        YYC.Class(B, {
                            Public: {}
                        });
                    }).toThrow();
                    expect(function () {
                        YYC.Class(B, {
                            Public: {
                                move: function () { }
                            }
                        });
                    }).toThrow();
                    expect(function () {
                        YYC.Class(B, {
                            Public: {
                                move: function () { },
                                a: 1
                            }
                        });
                    }).not.toThrow();
    
    
                    expect(function () {
                        YYC.Class(C, {
                            Public: {
                                move: function () { }
                            }
                        });
                    }).toThrow();
                });
                it("子类没有全部实现抽象父类的抽象成员时,抛出异常", function () {
                    var A = YYC.AClass({
                        Init: function (t) {
                            this.a = t;
                            this.b = 2;
                        },
                        Public: {
                            p: function () {
                                return 0;
                            }
                        },
                        Private: {
                            _m: 1
                        },
                        Protected: {
                            P_h: function () {
                                return this._m;
                            },
                            P_k: 3
                        },
                        Abstract: {
                            move: function () { },
                            u: 0,
                            t: function () { }
                        }
                    });
    
                    expect(function () {
                        YYC.Class(A, {
                            Init: function () {
                                this.b = 100;
                                this.base(200);
                            },
                            Public: {
                                u: 20
                            }
                        });
                    }).toThrow();
                });
                it("子类全部实现抽象父类的抽象成员时,不抛出异常", function () {
                    var A = YYC.AClass({
                        Init: function (t) {
                            this.a = t;
                            this.b = 2;
                        },
                        Public: {
                            p: function () {
                                return 0;
                            }
                        },
                        Private: {
                            _m: 1
                        },
                        Protected: {
                            P_h: function () {
                                return this._m;
                            },
                            P_k: 3
                        },
                        Abstract: {
                            move: function () { },
                            u: 0,
                            t: function () { }
                        }
                    });
                    var B = YYC.Class(A, {
                        Init: function () {
                            this.b = 100;
                            this.base(200);
                        },
                        Public: {
                            move: function () {
                                return this.P_h();
                            },
                            t: function () { },
                            u: 20
                        }
                    });
                    var C = YYC.Class(B, {
                        Public: {
                            move: function () {
                                var baseResult = this.base();
    
                                return baseResult;
                            },
                            t: function () { }
                        }
                    });
    
                    var b = new B();
                    var c = new C();
    
                    expect([b.a, b.b]).toEqual([200, 2]);
                    expect([b.p(), b.move(), b.u]).toEqual([0, 1, 20]);
                    expect(c.move()).toEqual(1);
                });
            });
        });
    
    
        describe("测试接口Interface", function () {
            it("可以继承多个接口", function () {
                var A = YYC.Interface("m1");
                var B = YYC.Interface("m2");
                var C = YYC.Interface([A, B], "m3");
                var D = YYC.Interface([A, B], ["m3"]);
                var E = YYC.Interface([A, B], ["m3"], ["a"]);
                var F = YYC.Interface(A, "m2");
    
                expect(C.prototype.Interface_m1).toBeExist();
                expect(C.prototype.Interface_m2).toBeExist();
                expect(C.prototype.Interface_m3).toBeExist();
    
                expect(D.prototype.Interface_m1).toBeExist();
                expect(D.prototype.Interface_m2).toBeExist();
                expect(D.prototype.Interface_m3).toBeExist();
    
                expect(E.prototype.Interface_m1).toBeExist();
                expect(E.prototype.Interface_m2).toBeExist();
                expect(E.prototype.Interface_m3).toBeExist();
                expect(E.prototype.Interface_a).toEqual(0);
    
                expect(F.prototype.Interface_m1).toBeExist();
                expect(F.prototype.Interface_m2).toBeExist();
            });
        });
    
        describe("集成测试", function () {
            it("测试解决“若父类的属性为引用类型(数组或对象)a,则如果子类的实例s1对a进行修改或者sub调用修改a的方法,则第二次创建实例s2的a为修改过后的a!”的问题", function () {
                var Parent = YYC.AClass({
                    Init: function () {
                        console.log("Parent Init!");
                    },
                    Public: {
                        a: [],
                    }
                });
                var Sub = YYC.Class(Parent, {
                    Init: function () {
                    },
                    Public: {
                    }
                });
    
                var t = new Sub();
                t.a.push("a");
                var m = new Sub();
    
                expect(m.a).toEqual([]);
            });
            it("测试解决“若父类Parent的属性为引用类型(数组或对象)a,有两个子类Sub1、Sub2。如果子类Sub1的实例s1对a进行修改或者sub调用修改a的方法,则子类Sub2的实例的a为修改过后的a!”的问题", function () {
                var Parent = YYC.AClass({
                    Init: function () {
                        console.log("Parent Init!");
                    },
                    Public: {
                        a: [],
                        add: function () {
                            this.a.push("a");
                        }
                    }
                });
                var Sub1 = YYC.Class(Parent, {
                    Init: function () {
                    },
                    Public: {
                    }
                });
                var Sub2 = YYC.Class(Parent, {
                    Init: function () {
                    }
                });
    
                var t = new Sub1();
                t.a.push("a");
                var k = new Sub2();
    
                expect(k.a).toEqual([]);
    
            });
            it("测试解决“若A1为抽象类,A2(抽象类)继承于A1,B(类)继承于A2,A1、A2、B都有同名方法a,A2和B在a方法中都通过this.baseClass调用父类同名方法。则如果B的实例b调用a方法,则A2、B的a方法中的this.baseClass均指向A2(照理说A2的this.baseClass应该指向A1)!”的问题", function () {
                var A1 = YYC.AClass({
                    Public: {
                        arr: [],
                        a: function () {
                            this.arr.push(1);
                        }
                    }
                });
                var A2 = YYC.AClass(A1, {
                    Public: {
                        a: function () {
                            this.arr.push(2);
                            this.baseClass.a.call(this, null);
                        }
                    }
                });
                var B = YYC.Class(A2, {
                    Public: {
                        a: function () {
                            this.arr.push(3);
                            this._baseClass.a.call(this, null);
    
                            return this.arr;
                        }
                    }
                });
                var b = new B();
    
                expect(b.a()).toEqual([3, 2, 1]);
            });
        });
    });
    View Code

    最终的YOOP代码:

    (function () {
    
        window.YYC = window.YYC || {};
    
        /************************************************** String对象扩展 ************************************************************/
        if (!String.prototype.contain) {
            String.prototype.contain = function (str) {
                var reg = new RegExp(str);  //str需要转义
                if (this.match(reg)) {
                    return true;
                }
                else {
                    return false;
                }
            }
        }
    
        /*****************************************************************************************************************************/
            //获得在原型prototype中不存在同名的str。
            //如果有同名,则加上前缀"_"
        function getNoRepeatStrInPrototype(prototype, str) {
            var new_str = "";
    
            if (!prototype[str]) {
                return str;
            }
            new_str = "_" + str;
    
            return arguments.callee(prototype, new_str);
        }
    
    
        function extendDeep(parent, child) {
            var i = null,
                len = 0,
                toStr = Object.prototype.toString,
                sArr = "[object Array]",
                sOb = "[object Object]",
                type = "",
                _child = null;
    
            //数组的话,不获得Array原型上的成员。
            if (toStr.call(parent) === sArr) {
                _child = child || [];
    
                for (i = 0, len = parent.length; i < len; i++) {
                    type = toStr.call(parent[i]);
                    if (type === sArr || type === sOb) {    //如果为数组或object对象
                        _child[i] = type === sArr ? [] : {};
                        arguments.callee(parent[i], _child[i]);
                    } else {
                        _child[i] = parent[i];
                    }
                }
            }
            //对象的话,要获得原型链上的成员。因为考虑以下情景:
            //类A继承于类B,现在想要拷贝类A的实例a的成员(包括从类B继承来的成员),那么就需要获得原型链上的成员。
            else if (toStr.call(parent) === sOb) {
                _child = child || {};
    
                for (i in parent) {
                    type = toStr.call(parent[i]);
                    if (type === sArr || type === sOb) {
                        _child[i] = type === sArr ? [] : {};
                        arguments.callee(parent[i], _child[i]);
                    } else {
                        _child[i] = parent[i];
                    }
                }
            }
            else {
                _child = parent;
            }
    
            return _child;
        };
        function getFunctionName(fn) {
            var name = "";
    
            if (!fn) {
                return null;
            }
    
            name = fn.toString().match(/^.*function\s*([^\(]*)/);
            return name === null ? name : name[1];
        };
    
        function isArray(val) {
            return Object.prototype.toString.call(val) === "[object Array]";
        };
    
        /*
         Structure写成原型形式,而Interface、AClass、Class不写成原型形式!(如写成:
         Interface.prototype = (function(){
         function I(){
         };
    
         return {
         ...
         };
         }());
         )
         因为如果写成原型形式,则Interface/AClass/Class的实例就共享同一个I/A/F类!这样会造成不同的类之间互相干扰!
         */
    
    
        (function () {
            function Interface() {
                var that = this;
    
                this.parent = null;
                this.method = null;
                this.attribute = null;
    
                function I() {
                }
    
                function _getByParent(_parent, _method, _attribute) {
                    if (_hasParent(_parent)) {
                        _checkInheritInterface(_parent);
                        that.parent = isArray(_parent) ? _parent : [_parent];
    
                        //形如“Interface(Parent, "A", "B", "GetName");”
                        if (_method && !isArray(_method)) {
                            that.method = Array.prototype.slice.call(arguments, 1);
                            that.attribute = null;
                        }
                        //形如“Interface(Parent, ["A", "B", "GetName"], ["a", "c"]);”
                        else {
                            that.method = _method;
                            that.attribute = _attribute;
                        }
                    }
                    else {
                        that.parent = null;
                        //形如“Interface("A", "B", "GetName");”
                        if (_parent && !isArray(_parent)) {
                            that.method = Array.prototype.slice.call(arguments, 0);
                            that.attribute = null;
                        }
                        //形如“Interface(["A", "B", "GetName"], ["a", "c"]);”
                        else {
                            that.method = arguments[0];
                            that.attribute = arguments[1];
                        }
                    }
    
                    _checkMethod();
                };
                function _hasParent(_parent) {
                    return typeof _parent === "function" || (isArray(_parent) && typeof _parent[0] === "function");
                };
                function _checkInheritInterface(_parent) {
                    var i = 0,
                        len = 0;
    
                    for (i = 0, len = _parent.length; i < len; i++) {
                        if (getFunctionName(_parent[i]) !== "I") {
                            throw new Error("Interface must inherit interface!");
                        }
                    }
                };
                function _checkMethod() {
                    if (!that.method) {
                        throw new Error("Interface must has methods");
                    }
                };
                function _inherit() {
                    var i = 0,
                        len = 0;
    
                    for (i = 0, len = that.parent.length; i < len; i++) {
                        extendDeep(that.parent[i].prototype, I.prototype);
                    }
                    I.prototype.constructor = I;
                };
                function _addMethod() {
                    var i = 0,
                        len = 0;
    
                    for (i = 0, len = that.method.length; i < len; i++) {
                        if (that.method[i] === undefined) {
                            continue;
                        }
                        //加上前缀“Interface_”
                        I.prototype["Interface_" + that.method[i]] = function () {
                            throw new Error("This method must be overwrited!");
                        };
                    }
                };
                function _addAttribute() {
                    var i = 0,
                        len = 0;
    
                    if (that.attribute) {
                        if (!isArray(that.attribute)) {
                            throw new Error("Attribute must be array!");
                        }
                        else {
                            for (i = 0, len = that.method.length; i < len; i++) {
                                //加上前缀“Interface_”
                                I.prototype["Interface_" + that.attribute[i]] = 0;
                            }
                        }
                    }
                };
    
                this.buildInterface = function (_parent, _method, _attribute) {
                    _getByParent(_parent, _method, _attribute);
                    if (this.parent) {
                        _inherit();
                    }
                    _addMethod();
                    _addAttribute();
    
                    return I;
                };
            };
    
            YYC.Interface = function (_parent, _method, _attribute) {
                return new Interface().buildInterface(_parent, _method, _attribute);
            };
        }());
    
        (function () {
    
            function Structure() {
            };
            Structure.prototype = (function () {
                return {
                    _addToImplementMap: function (name, func) {
                        this.implementaionMap[name] = func;
                    },
                    _prepareCheckFor: function (module) {
                        var name = null;
    
                        if (module) {
                            for (name in module) {
                                if (module.hasOwnProperty(name)) {
                                    this._prepareCheckForSpecial(name, module);
                                    this._addToImplementMap(name, module[name]);
                                }
                            }
                        }
                    },
                    _prepareCheckForSpecial: function (name, module) {
                        this._addVirtualToImplementMap(name, module);
                    },
                    _addVirtualToImplementMap: function (name, module) {
                        var name2 = "";
    
                        if (name === "Virtual") {
                            for (name2 in module[name]) {
                                if (module[name].hasOwnProperty(name2)) {
                                    this._addToImplementMap(name2, module[name][name2]);
                                }
                            }
                        }
                    },
                    P_checkImplementationOfAbstract: function () {
                        var name = "",
                            parentClass = this.parentClass;
    
                        if (this.parentClass) {
                            for (name in parentClass.prototype) {
                                if (parentClass.prototype.hasOwnProperty(name)) {
                                    if (name === "constructor") {
                                        continue;
                                    }
                                    if (name.contain("Abstract_")) {
                                        if (typeof parentClass.prototype[name] === "function") {
                                            this._checkAbstractMethod(name);
                                        }
                                        else {
                                            this._checkAbstractAttribute(name);
                                        }
                                    }
                                }
                            }
                        }
                    },
                    _checkAbstractMethod: function (name) {
                        var parentClass = this.parentClass,
                            implementaionMap = this.implementaionMap;
    
                        if (this._noMethodForAbstract(implementaionMap, name) && this._noMethodForAbstract(parentClass.prototype, name)) {
                            throw new Error("Abstract method '" + name + "' must be overwrited!");
                        }
                    },
                    _checkAbstractAttribute: function (name) {
                        var parentClass = this.parentClass,
                            implementaionMap = this.implementaionMap;
    
                        if (this._noAttritubeForAbstract(implementaionMap, name) && this._noAttritubeForAbstract(parentClass.prototype, name)) {
                            throw new Error("Abstract attribute '" + name + "' must be overwrited!");
                        }
                    },
                    P_checkImplementationOfInterface: function (_interface) {
                        var name = "";
    
                        for (name in _interface.prototype) {
                            if (!name.contain("Interface_")) {
                                continue;
                            }
                            if (typeof _interface.prototype[name] === "function") {
                                this._checkInterfaceMethod(name);
                            }
                            else {
                                this._checkInterfaceAttribute(name);
                            }
                        }
                    },
                    _checkInterfaceMethod: function (name) {
                        var implementaionMap = this.implementaionMap,
                            parentClassPrototype = this.parentClass ? this.parentClass.prototype : {};
    
                        if (this._noMethodForInterface(implementaionMap, name) && this._noMethodForInterface(parentClassPrototype, name)) {
                            throw new Error("Interface method '" + name + "' must be overwrited!");
                        }
                    },
                    _checkInterfaceAttribute: function (name) {
                        var implementaionMap = this.implementaionMap,
                            parentClassPrototype = this.parentClass ? this.parentClass.prototype : {};
    
                        if (this._noAttritubeForInterface(implementaionMap, name) && this._noAttritubeForInterface(parentClassPrototype, name)) {
                            throw new Error("Interface attribute '" + name + "' must be overwrited!");
                        }
                    },
                    _noMethodForAbstract: function (_class, name) {
                        return _class[name.slice(9)] === undefined || typeof _class[name.slice(9)] !== "function";
                    },
                    _noAttritubeForAbstract: function (_class, name) {
                        return _class[name.slice(9)] === undefined || typeof _class[name.slice(9)] === "function";
                    },
                    _noMethodForInterface: function (_class, name) {
                        return _class[name.slice(10)] === undefined || typeof _class[name.slice(10)] !== "function";
                    },
                    _noAttritubeForInterface: function (_class, name) {
                        return _class[name.slice(10)] === undefined || typeof _class[name.slice(10)] === "function";
                    },
                    P_addAbstract: function (abstract) {
                        var name = "",
                            _class = this.P_class;
    
                        for (name in abstract) {
                            if (abstract.hasOwnProperty(name)) {
                                //抽象方法前面加"Abstract_"前缀
                                _class.prototype["Abstract_" + name] = abstract[name];
                            }
                        }
                    },
                    //加入虚方法(不能为虚属性)
                    P_addVirtualAndCheck: function (virtual) {
                        var name = "",
                            _class = this.P_class;
    
                        for (name in virtual) {
                            if (virtual.hasOwnProperty(name)) {
                                if (typeof virtual[name] !== "function") {
                                    throw new Error("Virtual attribute is not allowed!");
                                }
                                else {
                                    _class.prototype[name] = virtual[name];
                                }
                            }
                        }
                    },
                    P_addStaticMember: function () {
                        var Static = null,
                            k = null,
                            _class = this.P_class,
                            prop = this.prop;
    
                        Static = prop.Static ? prop.Static : null;
    
                        for (k in Static) {
                            _class[k] = Static[k];
                        }
                    },
                    P_inherit: function () {
                        var _class = this.P_class,
                            parentClass = this.parentClass;
    
                        _class.prototype = extendDeep(parentClass.prototype);
                        _class.prototype.constructor = _class;
    
                        // 如果父类存在,则实例对象的baseClass指向父类的原型。
                        // 这就提供了在实例对象中调用父类方法的途径。
                        //baseClass的方法是指向this.parentClass.prototype的,不是指向(子类)的!
                        _class.prototype[getNoRepeatStrInPrototype(parentClass.prototype, "baseClass")] = parentClass.prototype;
                    },
                    P_addInit: function () {
                        var _class = this.P_class,
                            parentClass = this.parentClass,
                            prop = this.prop;
    
                        if (prop.Init) {
                            if (parentClass &&
                                typeof prop.Init === "function" &&
                                typeof _class.prototype.Init === "function") {
                                _class.prototype.Init = function (name) {
                                    return function () {
                                        this.base = parentClass.prototype[name];
    
                                        return prop[name].apply(this, arguments);
                                    };
                                }("Init");
                            }
                            else {
                                _class.prototype.Init = prop.Init;
                            }
                        }
                    },
                    P_addPrivateMember: function () {
                        var name = null,
                            _class = this.P_class,
                            private = this.prop.Private;
    
                        if (private) {
                            for (name in private) {
                                if (private.hasOwnProperty(name)) {
                                    _class.prototype[name] = private[name];
                                }
                            }
                        }
                    },
                    P_addPublicMember: function () {
                        var name = null;
    
                        if (this.prop.Public) {
                            for (name in this.prop.Public) {
                                if (this.prop.Public.hasOwnProperty(name)) {
                                    if (this.P_addSpecial("Public", name) === "continue") {
                                        continue;
                                    }
                                    this._addPublic(name);
                                }
                            }
                        }
                    },
                    _addPublic: function (name) {
                        var parentClass = this.parentClass,
                            prop = this.prop,
                            P_class = this.P_class;
    
                        if (parentClass &&
                            typeof prop.Public[name] === "function" &&
                            typeof P_class.prototype[name] === "function") {
                            P_class.prototype[name] = function (name) {
                                return function () {
                                    this.base = parentClass.prototype[name];
    
                                    return prop.Public[name].apply(this, arguments);
                                };
                            }(name);
                        }
                        else {
                            P_class.prototype[name] = prop.Public[name];
                        }
                    },
                    P_prepareCheck: function () {
                        this._prepareCheckFor(this.prop.Public);
                        this._prepareCheckFor(this.prop.Protected);
                    },
                    P_addProtectedMember: function () {
                        var name = null;
    
                        if (this.prop.Protected) {
                            for (name in this.prop.Protected) {
                                if (this.prop.Protected.hasOwnProperty(name)) {
                                    if (this.P_addSpecial("Protected", name) === "continue") {
                                        continue;
                                    }
                                    this.P_class.prototype[name] = this.prop.Protected[name];
                                }
                            }
                        }
                    }
                }
            }());
    
            //创建抽象类
            //抽象类能够继承接口、抽象类以及实体类,但此处约定抽象类只能继承接口和抽象类,不能继承实体类!
            //(这样方便判断抽象类是否包含全部的父类(接口/抽象类)成员)
    
            function AClass() {
                var that = this;
    
                this.P_class = A;
                this.implementaionMap = {};
                this.parentClass = null;
                this.interface = null;
                this.prop = null;
    
                // 创建的类(构造函数)
                function A() {
                };
    
                function __getByParent(args) {
                    var _parent = args[0],
                        _prop = args[1];
    
                    __checkOnlyOneParentClass(args);
    
                    if (_prop === undefined) {
                        that.prop = _parent;
                        that.parentClass = null;
                        that.interface = null;
                    }
                    //{Class: xx, Interface: xx}
                    else if (typeof _parent === "object") {
                        if (!_parent.Class && !_parent.Interface) {
                            throw new Error("Please add AbstractClass or Interface!");
                        }
                        that.parentClass = _parent.Class;
                        if (isArray(_parent.Interface)) {
                            that.interface = _parent.Interface;
                        }
                        else if (typeof _parent.Interface === "function") {
                            that.interface = [_parent.Interface];
                        }
                        that.prop = _prop;
                    }
                    //直接为xx抽象类
                    else if (typeof _parent === "function") {
                        that.parentClass = _parent;
                        that.interface = null;
                        that.prop = _prop;
                    }
                    else {
                        throw new Error("arguments is not allowed!");
                    }
                    if (__isInheritFromClass()) {
                        throw new Error("AbstractClass can't inherit class!");
                    }
                };
                function __checkOnlyOneParentClass(args) {
                    if (args.length >= 3) {
                        throw new Error("AbstractClass can only inherit from one parentClass");
                    }
    
                    if (args[0].Class) {
                        if (isArray(args[0].Class) && args[0].Class.length >= 2) {
                            throw new Error("AbstractClass can only inherit from one parentClass");
                        }
                    }
                };
                function __isInheritFromClass() {
                    return getFunctionName(that.parentClass) === "F";
                };
                this.P_inherit = function () {
                    var parentClass = this.parentClass;
    
                    if (this.parentClass) {
                        A.prototype = extendDeep(parentClass.prototype);
                        A.prototype.constructor = A;
    
                        // 如果父类存在,则实例对象的baseClass指向父类的原型。
                        // 这就提供了在实例对象中调用父类方法的途径。
                        //baseClass的方法是指向this.parentClass.prototype的,不是指向(子类)的!
                        A.prototype[getNoRepeatStrInPrototype(parentClass.prototype, "baseClass")] = parentClass.prototype;
                    }
    
                    if (this.interface) {
                        var i = 0,
                            len = 0;
    
                        for (i = 0, len = this.interface.length; i < len; i++) {
                            extendDeep(this.interface[i].prototype, A.prototype);
                        }
                    }
                };
                this.P_addSpecial = function (moduleName, name) {
                    if (name === "Abstract") {
                        this.P_addAbstract(this.prop[moduleName][name]);
                        return "continue";
                    }
                    if (name === "Virtual") {
                        this.P_addVirtualAndCheck(this.prop[moduleName][name]);
                        return "continue";
                    }
                    return null;
                };
    
                this.buildAClass = function (args) {
                    __getByParent(args);
    
                    this.P_inherit();
    
                    //抽象类本身因为不能实例化,所以不在A中调用构造函数Init。
                    //抽象类中的构造函数供子类构造函数中调用。
                    this.P_addInit();
                    this.P_addPrivateMember();
                    this.P_addProtectedMember();
                    this.P_addPublicMember();
                    this.P_addStaticMember();
                    __addOuterAbstract();
                    __addOuterVirtual();
    
                    this.P_prepareCheck();
    
                    return A;
                };
    
                //放到外面的抽象成员,默认为公有抽象成员
                function __addOuterAbstract() {
                    if (that.prop.Abstract) {
                        that.P_addAbstract(that.prop.Abstract);
                    }
                };
                function __addOuterVirtual() {
                    if (that.prop.Virtual) {
                        that.P_addVirtualAndCheck(that.prop.Virtual);
                    }
                };
            };
    
            AClass.prototype = new Structure();
    
            //创建普通类
            //父类_parent可以为{Class: xx, Interface: xx},或者直接为xx类
            function Class() {
                var that = this;
    
                this.implementaionMap = {};
                this.parentClass = null;
                this.interface = null;
                this.prop = null;
    
                this.P_class = F;
                //当前是否处于创建类的阶段。
                this.initializing = false;
    
    
                // 创建的类(构造函数)
                function F() {
                    var self = this,
                        args = arguments;
    
                    function _restorePrototype() {
                        extendDeep(F.prototype, self);
                    };
                    function _init() {
                        // 如果当前处于实例化类的阶段,则调用构造函数Init
                        if (!that.initializing) {
                            self.Init && self.Init.apply(self, args);
                        }
                    };
    
                    _restorePrototype();
                    _init();
    
                    /*不能删除私有成员和保护成员!否则类的成员就不能调用到私有和保护的成员了(因为已经删除了)!
                     对象的创建算法参考http://www.cnblogs.com/TomXu/archive/2012/02/06/2330609.html
    
    
    
    
                     //删除私有成员和保护成员,这样外界就不能访问私有和保护成员了!
                     for (name in this) {
                     if (name.search(/(^_)|(^P_)/) !== -1) {
                     delete F.prototype[name];
                     //                                                    this[name] = null;
                     }
    
                     }
                     */
                }
    
                function __getByParent(args) {
                    var _parent = args[0],
                        _prop = args[1];
    
                    __checkOnlyOneParentClass(args);
    
                    if (_prop === undefined) {
                        that.prop = _parent;
                        that.parentClass = null;
                        that.interface = null;
                    }
                    //{Class: xx, Interface: xx}
                    else if (typeof _parent === "object") {
                        if (!_parent.Class && !_parent.Interface) {
                            throw new Error("Please add Class or Interface!");
                        }
                        that.parentClass = _parent.Class;
                        if (isArray(_parent.Interface)) {
                            that.interface = _parent.Interface;
                        }
                        else if (typeof _parent.Interface === "function") {
                            that.interface = [_parent.Interface];
                        }
                        that.prop = _prop;
                    }
                    //直接为xx类
                    else if (typeof _parent === "function") {
                        that.parentClass = _parent;
                        that.interface = null;
                        that.prop = _prop;
                    }
                    else {
                        throw new Error("arguments is not allowed!");
                    }
                };
                function __checkOnlyOneParentClass(args) {
                    if (args.length >= 3) {
                        throw new Error("class can only inherit from one parentClass");
                    }
    
                    if (args[0].Class) {
                        if (isArray(args[0].Class) && args[0].Class.length >= 2) {
                            throw new Error("class can only inherit from one parentClass");
                        }
                    }
                };
                this.P_addSpecial = function (moduleName, name) {
                    if (name === "Abstract") {
                        throw new Error("class can't have abstract members");
                    }
                    if (name === "Virtual") {
                        this.P_addVirtualAndCheck(this.prop[moduleName][name]);
                        return "continue";
                    }
                    return null;
                };
                this.buildClass = function (args) {
                    __getByParent(args);
    
                    if (this.parentClass) {
                        this.initializing = true;
                        this.P_inherit();
                        this.initializing = false;
                    }
    
                    this.P_addInit();
                    this.P_addPrivateMember();
                    this.P_addProtectedMember();
                    this.P_addPublicMember();
                    this.P_addStaticMember();
                    __addOuterAbstract();
                    __addOuterVirtual();
    
                    this.P_prepareCheck();
                    this.P_checkImplementationOfAbstract();
                    __checkEachImplementationOfInterface();
    
                    return F;
                };
                function __checkEachImplementationOfInterface() {
                    if (that.interface) {
                        var i = 0,
                            len = 0;
    
                        for (i = 0, len = that.interface.length; i < len; i++) {
                            that.P_checkImplementationOfInterface(that.interface[i]);
                        }
                    }
                    if (__hasInterfaceInheritFromParentClass()) {
                        that.P_checkImplementationOfInterface(that.parentClass);
                    }
                };
                function __hasInterfaceInheritFromParentClass() {
                    var name = "";
    
                    for (name in F.prototype) {
                        if (F.prototype.hasOwnProperty(name)) {
                            if (name.contain("Interface_")) {
                                return true;
                            }
                        }
                    }
    
                    return false;
                };
                function __addOuterAbstract() {
                    if (that.prop.Abstract) {
                        throw new Error("class can't have abstract members!");
                    }
                };
                function __addOuterVirtual() {
                    if (that.prop.Virtual) {
                        that.P_addVirtualAndCheck(that.prop.Virtual);
                    }
                };
            };
    
            Class.prototype = new Structure();
    
            /*
             下面的写法有问题!因为只有载入YOOP.js时,创建了AClass的实例。
             调用YYC.AClass时,只是引用该实例的buildAClass,而不会再创建AClass实例。
             也就是说,所有YYC.AClass都共用一个AClass的实例!共用AClass实例的属性(如parent等)!
    
             YYC.AClass = new AClass().buildAClass;
             */
    
    
            YYC.AClass = function () {
                return new AClass().buildAClass(arguments);
            };
            YYC.Class = function () {
                return new Class().buildClass(arguments);
            };
        }());
    }());
    View Code

    总结

    我花了5天的时间来对YOOP进行重构,这样效率其实是比较低下的。我们应该采用TDD开发,在需要重构的时候立马重构。

    因为随着人们对问题研究的深入,人们对问题的了解也越来越多,所以需要及时的反馈修正,对之前做的设计或代码进行修改,然后运行测试,保证测试的通过,然后再进行下一步的研究。这是一个迭代的过程,每次重构,都能反映自己的最新的理解。

    为了保证代码质量,为了便于二次开发扩展,为了增强可读性,为了反映自己最新的理解,为了追求代码之美、设计之美,都需要我们在坚实的测试套件下,不断地重构改进。

    需要注意的是,不仅是产品代码需要重构,测试代码也一样需要重构。

    对于我们个人的修炼而言,应该时刻地重构;对于工程方面而言,有时为了赶进度,会对质量方面要求降低。但是作为程序员,应该对自己编写的代码负责,在赶进度的情况下,我们应该在项目结束或相对轻松的时间里,对代码进行重构,而且可以进行抽象、封装,提炼出自己的产品和文档。

    只有通过不断地改进、总结,我们才能不断地进步。

  • 相关阅读:
    steam
    node 循序渐进
    node 常用指令 node 扩展链接
    window 常用指令
    web API
    SHAREPOINT
    div设置边框黑框显示
    sharepoint更新多行文本webparth
    sharepoint读取启用了追加功能的多行文本的历史版本记录
    JS实现多附件上传(asp.net)
  • 原文地址:https://www.cnblogs.com/chaogex/p/3126797.html
Copyright © 2011-2022 走看看