Javascript OOP框架YOOP重构实践(下)
继续重构
提取基类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(); }); });
通过重构实践(一)的重构,我发现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); }; }());
重构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; }; };
增加测试
增加测试"子类虚方法实现抽象父类的抽象方法时,不抛出异常"、"非抽象类定义抽象成员时抛出异常":

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(); });
重构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]); }); }); });
最终的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); }; }()); }());
总结
我花了5天的时间来对YOOP进行重构,这样效率其实是比较低下的。我们应该采用TDD开发,在需要重构的时候立马重构。
因为随着人们对问题研究的深入,人们对问题的了解也越来越多,所以需要及时的反馈修正,对之前做的设计或代码进行修改,然后运行测试,保证测试的通过,然后再进行下一步的研究。这是一个迭代的过程,每次重构,都能反映自己的最新的理解。
为了保证代码质量,为了便于二次开发扩展,为了增强可读性,为了反映自己最新的理解,为了追求代码之美、设计之美,都需要我们在坚实的测试套件下,不断地重构改进。
需要注意的是,不仅是产品代码需要重构,测试代码也一样需要重构。
对于我们个人的修炼而言,应该时刻地重构;对于工程方面而言,有时为了赶进度,会对质量方面要求降低。但是作为程序员,应该对自己编写的代码负责,在赶进度的情况下,我们应该在项目结束或相对轻松的时间里,对代码进行重构,而且可以进行抽象、封装,提炼出自己的产品和文档。
只有通过不断地改进、总结,我们才能不断地进步。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?