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/Strategy。code
Replace Type Code with Subclasses的主要做用實際上是搭建一個舞臺,讓Replace Conditional with Polymorphism得以一展身手。若是宿主類中並無出現條件表達式,那麼Replace Type Code with Class更合適,風險也比較低。對象
使用Replace Type Code with Subclasses 的另外一個緣由就是,宿主類中出現了「只與具有特定類型碼之對象相關」的特性。完成本項重構後,你可使用Push Down Method和Push 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,將只與特定種類僱員相關的函數和字段推到相關的子類去。