1. 程式人生 > 實用技巧 >第11章 處理概括關係

第11章 處理概括關係

欄位上移(Pull Up Field)

1.概念:兩個子類擁有相同的欄位,將欄位移至超類。

2.動機:子類如果是分別開發的,可能具有重複的特性,特別是欄位容易重複,如果確認了欄位的使用方式很相似,就可以把它們歸到超類去。

函式上移(Pull Up Method)

1.概念:有些函式,在各個子類中產生完全相同的結果,則將函式移至超類。

2.動機:一種情況是類似欄位上移的動機,還有一種情況是子類的函式覆寫了超類的函式,卻仍然做著相同的工作,此時也需要將函式上移。

3.做法:注意因為子類中的函式並不相同,我們必須在超類中宣告它們的抽象函式。

建構函式本體上移(Pull Up Constructor Body)

1.概念:你在各個子類中擁有一些建構函式,它們的本體幾乎完全一致。則在超類中新建一個建構函式,並在子類建構函式中呼叫它。

2.動機:如果你看見各個子類中的函式有共同的行為,首先應該想到將它們的共同行為提煉到一個獨立函式中,然後將這個類提升為超類。對於建構函式來說,子類共同的行為就是“物件的構建”。

3.做法:

(1)在超類中定義一個建構函式。

(2)將子類建構函式中的共同程式碼搬移到超類建構函式中。

(3)將子類建構函式共同程式碼刪掉,改而呼叫新建的超類建構函式。

(4)編譯,測試。

//超類
class
Emploee { protected Employee(String name, String id) {
this.name = name; this.id = id; } }
//子類中呼叫
public Manager(String name, String id, int grade) {
    super(name, id);
    this.grade = grade;
}

函式下移(Push Down Method)

1.概念:超類中的某個函式只與部分(而非全部)子類有關,則將這個函式移到相關的那些子類中去。

欄位下移(Push Down Field)

1.概念:超類中的某個欄位只被部分(而非全部)子類用到,則將這個欄位移到需要它的那些子類去。

提煉子類(Extract Subclass)

1.概念:類中的某些特性只被某些(而非全部)例項用到,則新建一個子類,將上面說的那一部分特性移到子類中。

提煉超類(Extract Superclass)

1.概念:

兩個類有相似的特性,則為這兩個類建立一個超類,將相同特性移至超類。

提煉介面(Extract Interface)

1.概念:

若干客戶使用類介面中的同一子集,或者兩個類的介面有部分相同,則將相同的子集提煉到一個獨立介面中。

2.動機;

類彼此之間有很多種互用的方式,“使用一個類”通常意味著用到該類的所有責任區。但如果一組客戶只使用到類責任區中的一個特定子集,或者這個類需要與所有協助處理某些特定請求的類合作,面對這兩種情況,將這部分用到的職責分離出來就很有意義。這樣使用法更清晰,責任劃分更清晰。

摺疊繼承體系(Collapse Hierarchy)

1.概念:

超類和子類之間無太大區別,則將它們合為一體。

塑造模板函式(Form TemPlate Method)

1.你有一些子類,其中相應的某些函式以相同順序執行類似的操作,但各個操作的細節上有所不同。則將這些操作分別放進獨立函式中,並保持他們都有相同的簽名,於是原函式也就變得相同了,然後將原函式上移至超類。

(略,待細看)

以委託取代繼承(Replace Inheritance with Delegation)

1.概念:

某個子類只使用超類介面中的一部分,或是根本不需要繼承而來的資料,則在子類中新建一個欄位用以儲存超類,然後調整子類函式,令它改而委託超類,最後去掉兩者之間的繼承關係。

(委託:在A類中例項化B類物件,並在A類方法中通過例項出的B類物件返回B類的東西)

2.動機:

繼承雖好,但並不一定是你想要的。當一開始繼承了一個類,然後發現超類中很多操作並不真正適用於子類,則改用委託取代繼承。

3.做法:

濫用繼承的一個典型的範例就是讓stack類繼承Vector類,其中客戶端Stack只需要做4件事,push(), pop(), 還有從vector繼承來的size(), isEmpty():

//原式
class
MyStack extends Vector { public void push(Object element) { insertElement(element, 0); } public Object pop() { Object result = firstElement(); removeElementAt(0); return result; } }

(1)在子類中新建一個欄位,使其引用超類的一個例項,並將它們初始化為this。

(2)修改子類內的所有函式,讓它們不再使用超類,轉而使用上述的受託欄位,每次修改後,編譯並測試。

class Mystack extends Vector {
    private Vector vector = this;

    public void push(Object element) {
        vector.insertElementAt(element, 0);
    }

    public Object pop() {
        Object result = vector.firstElement();
        vector.removeElementAt(0);
        return result;
    }
}

(3)去除兩個類之間的繼承關係,新建一個受託類的物件賦給受託欄位。

(4)針對客戶端所用的每一個超類函式,為它新增一個簡單的委託函式。

class Mystack {
    private Vector vector = new Vector();

    //新增委託函式
    public int size() {
        return vector.size();
    }

    public boolean isEmpty() {
        return vector.isEmpty();
    }
}

以繼承取代委託(Replace Delegation with Inheritance)

1.概念:

你在兩個類之間使用委託關係,並經常為整個介面編寫許多極簡單的委託函式,則讓委託函式繼承受託類。

2.動機:

與“以委託取代繼承”相反,如果你發現自己需要使用受託類中所有函式,並花了很大力氣編寫所有極簡的委託函式時,用此重構。