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

某個子類只使用超類接口中的一部分,或是根本不須要繼承而來的數據。在子類中新建一個字段用以保存超類;調整子類函數,令它改而委託超類;而後去掉二者之間的繼承關係    java

                                           

動機函數

繼承是個好東西,但有時候它並非你要的。你經常會遇到這樣的狀況:一開始繼承了一個類,隨後發現超類中的許多操做並不真正適用於子類。這種狀況下,你所擁有的接口並未真正反映出子類的功能。或者,你可能發現你從超類中繼承了一大堆子類並不須要的數據,抑或你可能發現超類中的某些protected函數對子類並無什麼意義。工具

你能夠選擇容忍,並接受傳統說法:子類能夠只使用超類功能的一部分。但這樣作的結果是:代碼傳達的信息與你的意圖南轅北轍這是一種混淆,你應該將它去除。測試

若是以委託取代繼承,你能夠更清楚地代表:你只須要受託類的一部分功能。接口中的哪一部分應該被使用,哪一部分應該被忽略,徹底由你主導控制。這樣作的成本則是須要額外寫出委託函數,但這些函數都很是簡單,極少可能出錯。this

作法 spa

 1.在子類中新建一個字段,使其引用超類的一個實例,並將它初始化爲thiscode

2.修改子類內的全部函數,讓它們再也不使用超類,轉而使用上述那個受託字段。每次修改後,編譯並測試。對象

注意:你不能這樣修改子類中經過super調用超類函數的代碼,不然它們會陷入無限遞歸。這種函數只有在繼承關係被打破後才能修改。繼承

3.去除兩個類之間的繼承關係,新建一個受託類的對象賦給受託字段。遞歸

4.針對客戶端所用的每個超類函數,爲它添加一個簡單的委託函數

5.編譯,測試。

範例:

   濫用繼承的一個經典範例就是讓Stack類繼承Vector類---java 1.1的工具庫(java.util)剛好就是這樣作的。不過,做爲範例,咱們只給出一個比較簡單的形式:  

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

,只要看看MyStack的用戶,咱們就會發現,用戶只要它作4件事:push(), pop(),sieze(), 和isEmpty()。後兩個函數式從vector繼承來的。

把這裏的繼承關係改成委託關係。首先,在MyStack中新建一個字段,用以保存受託的Vector對象。一開始,把這個字段初始化爲this,這樣在重構進行過程當中,就能夠同時使用繼承和委託:

private Vector _vector = this;

如今,開始修改MyStack的函數,讓它們使用委託關係。首先從push()開始:

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

此時,編譯並測試,一切都將運轉如常。如今輪到pop();

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

修改完全部的子類函數後,咱們能夠打破與超類之間的聯繫了:

class MyStack{
  private Vector _vector = new Vector();
}

而後,對於Stack客戶端可能用到的每個Vector函數,都必須在MyStack中添加一個簡單的委託函數:

public int size(){
     return _vector.size();
}

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

如今,編譯並測試。若是忘記加入某個委託函數,編譯器會告訴咱們。

相關文章
相關標籤/搜索