給一個巨大的繼承體系的基類增加新的屬性,如何降低重構強度?
需要給一個巨大的繼承體系(語法樹節點)的基類Node增加parent屬性,並且在每個派生類的構造器中,對每個基類為Node的成員設置parent屬性為this,有沒有什麼好的方法,讓我可以不去挨個修改這94個class的構造函數?
語言是js,如果js有什麼特別方便的方法來做這件事,那再好不過了。
代碼舉例,應很多人要求換成javascript了
之前:
class Type {
constructor() {
}
}class Pointer extends Type{
/**
* @param {Type} t
*/
constructor(t) {
super();
this.referenceType = t;
}
}class Array extends Type{
/**
* @param {Type} t
*/
constructor(t) {
super();
this.elementType = t;
}
}//更多其它的派生類
現在:
class Type {
constructor() {
/**
* @type {Type}
*/
this.parent = null; //&<==========這裡 } } class Pointer extends Type{ /** * @param {Type} t */ constructor(t) { super(); this.referenceType = t; t.parent = this; //&<==========這裡 } } class Array extends Type{ /** * @param {Type} t */ constructor(t) { super(); this.elementType = t; t.parent = this; //&<==========這裡 } } //更多其它的派生類也要修改有沒有什麼好方法避免我挨個去修改Type的所有派生類?
我們不妨假設你原來的 JS (我就用 TS 寫了,更方便)是這樣:
class Type {
parent: Type;
}
class Pointer extends Type {
public type: Type;
constructor(t: Type) {
super();
this.type = t;
}
}
class Array_ extends Type {
public type: Type;
constructor(t: Type) {
super();
this.type = t;
}
}
思路是這樣的,你的 `t` 都在構造函數的參數列表裡,我們可以通過 `arguments.callee.caller` 獲取一個函數的調用著,在這裡 Type 的構造函數的調用者就是子類的構造函數,那麼我們又可以獲取它的參數列表。這樣如果你要改的東西都是參數的話,我們就可以遍歷參數列表來改它(假如就一個,位置固定啥的,那就直接改):
class Type {
parent: Type;
constructor () {
const parentArguments = arguments.callee.caller.arguments;
for (let i = 0; i &< parentArguments.length; ++i) {
parentArguments[i].parent = this;
}
}
}
class Pointer extends Type {
public type: Type;
constructor(t: Type) {
super();
this.type = t;
}
}
class Array_ extends Type {
public type: Type;
constructor(t: Type) {
super();
this.type = t;
}
}
我們可以檢驗一下:
const t = new Type();
const pointer = new Pointer(t);
console.log(pointer.type.parent === pointer) // true
不大規模修改是不可能的。你只有兩種選擇:
1、修改每一個類
2、把每一處new這些類的地方都改為函數調用,which is 更好但是更煩,可能需要改一千個地方
3、不理,然後在一些特殊的地方統一修改parent
因為有parent就代表子樹是被獨佔的。所以你還要做一個檢查:如果你用了一個已經有parent的東西去調用這些構造函數,那麼就地崩潰。所以這不僅僅是修改parent這麼簡單的事情,你還要再改之前看看他是不是undefined。
你可以選擇在整棵樹弄好之後,專門寫一個RecursivelySetParentBecauseTheCodeIsStupid函數,一整棵樹遞歸進去,把每一個東西的parent都賦值好。我猜你是在寫parser/codegen,在這種情況下,調用RecursivelySetParentBecauseTheCodeIsStupid就是最好的方案了,因為構造AST的出口不會太多。
唔,題主想要的是這個效果么?
但我覺得這樣很糟糕
struct Type {
Type* parent = this; //&<==========這裡
};
struct Pointer : Type{
Type* type;
Pointer(Type* t) {
type = t;
}
};
這樣不行么, 不過這裡是C++的語法
推薦閱讀:
※這個例子中的if else也要重構掉嗎?
※為什麼軟體開發需要重構?
TAG:JavaScript | 重構 | C | 編譯原理 | ECMAScript2015 |