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.rzrgm.cn/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.rzrgm.cn/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開發,在需要重構的時候立馬重構。
因為隨著人們對問題研究的深入,人們對問題的了解也越來越多,所以需要及時的反饋修正,對之前做的設計或代碼進行修改,然后運行測試,保證測試的通過,然后再進行下一步的研究。這是一個迭代的過程,每次重構,都能反映自己的最新的理解。
為了保證代碼質量,為了便于二次開發擴展,為了增強可讀性,為了反映自己最新的理解,為了追求代碼之美、設計之美,都需要我們在堅實的測試套件下,不斷地重構改進。
需要注意的是,不僅是產品代碼需要重構,測試代碼也一樣需要重構。
對于我們個人的修煉而言,應該時刻地重構;對于工程方面而言,有時為了趕進度,會對質量方面要求降低。但是作為程序員,應該對自己編寫的代碼負責,在趕進度的情況下,我們應該在項目結束或相對輕松的時間里,對代碼進行重構,而且可以進行抽象、封裝,提煉出自己的產品和文檔。
只有通過不斷地改進、總結,我們才能不斷地進步。
浙公網安備 33010602011771號