Replace Type Code with Subclasses (以子類取代類型碼)

Summary 你有一個不可變的類型碼,它會影響類的行爲。以子類取代這個類型碼。java

                                               

動機:函數

  若是你面對的類型碼不會影響宿主類的行爲,可使用Replace Type Code with Class來處理它們。但若是類型碼會影響宿主類的行爲,那麼最好的辦法就是藉助多態來處理變化行爲。測試

通常來講,這種狀況的標誌就是像switch這樣的條件表達式。這種條件表達式可能有兩種表現形式:switch語句或者if-then-else結構。不論哪一種形式,它們都是檢查類型碼值,並根據不一樣的值執行不一樣的動做。這種狀況下,你應該以Replace Conditional with Polymorphism進行重構,首先應該將類型碼替換爲可擁有多態性爲的繼承體系。這樣的一個繼承體系應該以類型碼的宿主類爲基類,並針對每一種類型碼各創建一個子類。編碼

爲創建這樣的繼承體系,最簡單的辦法就是Replace Type Code with Subclasses:以類型碼的宿主爲基類,針對每種類型碼創建相應的子類。spa

可是如下兩種狀況你不能那麼作:(1)類型碼值在對象建立以後發生了改變;(2)因爲某些緣由,類型碼素質類已經有了子類。若是你剛好面臨這兩種狀況之一,就須要使用Replace Type Code with State/Strategycode

Replace Type Code with Subclasses的主要做用實際上是搭建一個舞臺,讓Replace Conditional with Polymorphism得以一展身手。若是宿主類中並無出現條件表達式,那麼Replace Type Code with Class更合適,風險也比較低。對象

使用Replace Type Code with Subclasses 的另外一個緣由就是,宿主類中出現了「只與具有特定類型碼之對象相關」的特性。完成本項重構後,你可使用Push Down MethodPush Down Field將這些特性推到合適的子類去,以彰顯它們只與特定狀況相關這一事實。繼承

Replace Type Code with Subclasses的好處在於:它把「對不一樣行爲的瞭解」從類用戶那兒轉移到了類自身。若是須要再加入新的行爲變化,只需添加一個子類就好了。若是沒有多態機制,就必須找到全部條件表達式,並注意修改它們。所以,若是將來還有可能加入新行爲,這項重構將特別有價值。get

作法:it

1.使用Self Encapsulate Field將類型碼自我封裝起來

à若是類型碼被傳遞給構造函數,就須要將構造函數換成工廠函數。

2.爲類型碼的每個數值創建一個相應的子類。在每一個子類中覆寫類型碼的取值函數,使其返回相應的類型碼值。

à這個值被硬編碼與return語句中(例如,return 1)。這看起來很骯髒,但只是權宜之計。當全部case子句都被替換後,問題就解決了。

3.每創建一個新的子類,編譯並測試。

4.從超類中刪掉保存類型碼的字段。將類型碼訪問函數聲明爲抽象函數。

5.編譯,測試。

範例:

爲簡單起見,咱們仍是使用哪一個惱人又不切實際的「僱員/薪資」例子。咱們以Employee表示「僱員」:

class Employee...
    private int _type;
    static final int ENGINEER = 0;
    static final int SALESMAN = 1;
    static final int MANAGER =2;
    
    Employee (int type){
        _type = type;
    }

第一步是以Self Encapsulate Field將類型碼自我封裝起來:

int getType(){
    return _type;
}

因爲Employee構造函數接受類型碼做爲一個參數,因此我必須將它替換爲一個工廠函數:

static Employee create (int type){
    return new Employee(type);
}
private Employee (int type){
    _type = type;
}

如今,咱們能夠先創建一個子類Engineer表示「工程師」。首先創建這個子類,並在其中覆寫類型碼取值函數:

class Engineer extends Employee{
    int getType(){
       return Employee.ENGINEER; 
   }
}

同時應該修改工廠函數,令它返回一個合適的對象:

class Employee
    static Employee create(int type){
        if(type == ENGINEER){
            return new Engineer();
        }else{
            return new Employee(type);
        }    
    }

而後,繼續逐一地處理其餘類型碼,直到全部類型碼都被替換成子類爲止。此時咱們就能夠移除Employee中保存類型碼的字段,並將getType聲明爲一個抽象函數。如今,工廠函數看起來像這樣:

abstract int getType();

static Employee create(int type){
    switch (type){
        case ENGINEER:
          return new Engineer();
        case SALESMAN:
          return new Saleman();
        case MANAGER:
          return new Manager();  
        default:
            throw new IllegalArgumentException("Incorrect type code value");
    }
}

固然,咱們老是避免使用switch語句。但這裏只有一處用到switch語句,而且只用於決定建立何種對象,這樣的switch語句是能夠接受的。

很天然地,在創建了這些子類後,就應該使用Push Down Method和Push Down Field,將只與特定種類僱員相關的函數和字段推到相關的子類去。

相關文章
相關標籤/搜索