【Effective Java】條17:爲繼承類專門設計並提供文檔說明,否則不使用

【Effective Java】條16:複合優於繼承中我們已經提到過使用繼承的缺點。但如果是專爲繼承設計的,並提供文檔說明,那是排除在外的情形。下面看看怎麼專爲繼承設計類,並怎麼提供文檔說明。

  1. 該類的文檔需明確說明重寫任何方法的影響
    對於每個public或者protected的方法或者構造器,都需要指明該方法或者構造器調用了哪些可覆蓋的方法,以什麼順序,每個調用結果是如何影響後續的處理。最好還需要說明在哪種情形下類會調用可重寫的方法。

    JDK中,針對調用了可重寫方法的方法,註釋中在描述方法是做什麼的文檔後面,通常都添加了調用的說明,且通常都以This implementation開頭。如java.util.AbstractCollectionremove方法,說明remove是依賴於iteratorremove方法的:

    public boolean remove(Object o)
    
    Removes a single instance of the specified element from this collection, if it is present (optional operation). More formally, removes an element e such that (o==null ? e==null : o.equals(e)), if this collection contains one or more such elements. Returns true if this collection contained the specified element (or equivalently, if this collection changed as a result of the call).
    
    This implementation iterates over the collection looking for the specified element. If it finds the element, it removes the element from the collection using the iterator's remove method.
    
    Note that this implementation throws an UnsupportedOperationException if the iterator returned by this collection's iterator method does not implement the remove method and this collection contains the specified object.
  2. 類可以通過protected方法或者protected域來提供鉤子,關聯到內部工作流程中。如java.util.AbstractList中的removeRange方法:

    protected void removeRange(int fromIndex, int toIndex)
    
    Removes from this list all of the elements whose index is between fromIndex, inclusive, and toIndex, exclusive. Shifts any succeeding elements to the left (reduces their index). This call shortens the list by (toIndex - fromIndex) elements. (If toIndex==fromIndex, this operation has no effect.)
    This method is called by the clear operation on this list and its subLists. Overriding this method to take advantage of the internals of the list implementation can substantially improve the performance of the clear operation on this list and its subLists.
    
    This implementation gets a list iterator positioned before fromIndex, and repeatedly calls ListIterator.next followed by ListIterator.remove until the entire range has been removed. Note: if ListIterator.remove requires linear time, this implementation requires quadratic time.
    
    Parameters:
    fromIndex - index of first element to be removed
    toIndex - index after last element to be removed

    removeRange方法對於List實現的最終用戶並無多大意義。提供該方法的唯一目的在於使子類更易於提供對字列表的快速clear方法。若沒有removeRange方法,當在字列表上調用clear方法時,子類將不得不用平方級的時間來完成工作。==不是特別明白==

  3. 如果類是爲繼承設計,那麼最好的方法就是自己寫子類來測試是否暴露了不該暴露的接口

當然,在設計類繼承時,也需要注意以下幾點:
1. 構造器不應該調用(直接或間接)可重寫的方法。舉個反例:
“`
public class Super {
// Broken - constructor invokes an overridable method
public Super() {
overrideMe();
}

    public void overrideMe() {
    }
}

public final class Sub extends Super {
    private final Date date; // Blank final, set by constructor

    Sub() {
        date = new Date();
    }

    // Overriding method invoked by superclass constructor
    @Override public void overrideMe() {
        System.out.println(date);
    }

    //輸出null和當前時間。因爲先調用父類構造器。
    public static void main(String[] args) {
        Sub sub = new Sub();
        sub.overrideMe();
    }
}
```

2. 實現clone或者Serializable接口的類,clonereadObject方法都不能調用可重寫的方法(類似於構造器)
3. 如果爲繼承設計的類實現Serializable接口,則readResolvewriteReplace方法需要用protected修飾,而不是private,否則會被子類忽略

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章