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开发,在需要重构的时候立马重构。

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

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

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

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

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

原文地址:https://www.cnblogs.com/chaogex/p/3126797.html