Summary:你在兩個類之間使用委託關係,並常常爲整個接口編寫許多極簡單的委託函數。讓委託類繼承受託類java
動機:函數
本重構與Replace Inheritance with Delegation 偏偏相反。若是你發現本身須要使用受託類中的全部函數,而且費了很大力氣編寫全部極簡的委託函數,本重構能夠幫助你輕鬆回頭使用繼承。測試
兩條告誡需牢記於心。首先,若是你並無使用受託類的全部函數,那麼就不該該使用Replace Delegation With Inheritance,由於子類應該老是遵循超類的接口。若是過多的委託函數讓你煩心,你有別的選擇:你能夠經過Remove Middle Man 讓客戶端本身調用受託看書,也可使用Extract Superclass 將兩個類接口相同的部分提煉到超類中,而後讓兩個類都繼承這個新的超類;你還能夠用相似的手法使用Extract Interface。spa
另外一種須要小心的狀況是:受託對象被不止一個其餘對象共享,並且受託對象是可變的。在這種狀況下,你就不能將委託關係替換爲繼承關係,由於這樣就沒法再共享數據了。共享數據是必須由委託關係承擔的一種責任,你沒法把它轉給繼承關係。若是受託對象是不可變的,數據共享就不成問題,由於你大可放心地複製對象,誰都不會知道設計
作法:code
1.讓委託端成爲受託端的一個子類對象
2. 編譯。繼承
注意:此時某些函數可能會發生衝突:它們可能有相同的名稱,但在返回類型、異常指定或可見程度方面有所差別。你可使用Rename Method解決此類問題。遞歸
3.將受託字段設爲該字段所處對象自己。接口
4.去掉簡單的委託函數。
5.編譯並測試。
6.將全部其餘設計委託關係的代碼,改成調用對象自身。
7.移除受託字段
範例:
下面是一個簡單的Employee類,將一些函數委託給另外一個一樣簡單的Person類:
class Employee{
Person _person = new Person();
public String getName(){
return _person.getName();
}
public void seName(String arg){
_person.setName(arg);
}
public String toString(){
return "Emp:" + _person.getLastName();
}
}
class Person(){
String _name;
public String getName(){
return _name;
}
public void setName(String arg){
_name = arg;
}
public String getLastName(){
return _name.subString(_name.lastIndexOf(' ') + 1);
}
}
第一步,只需聲明二者之間的繼承關係:
class Employee extends Person
此時,若是有任何函數發生衝突,編譯器會提醒咱們。若是某幾個函數的名稱相同,但返回類型不一樣或拋出不一樣的異常,它們之間就會出現衝突。全部此類問題均可以經過Rename Method加以解決。爲求簡化,範例中哦沒有列出這些麻煩的狀況。
下一步要將受託字段設值爲該字段所處對象自身。同時,必須先刪掉全部簡單的委託函數(例如getName()和setName())。若是劉翔這種函數,就會由於無限遞歸而引發系統調用棧溢出。在此範例中,咱們應該把Employee的getName()和setName()拿掉。
一旦Employee能夠正常工做了,就修改其中用到委託函數的代碼,讓它們直接調用從超類繼承而來的函數:
public String toString(){
return "Emp: " + getLastName();
}
擺脫全部涉及委託關係的函數後,也就能夠擺脫_person這個受託字段了。