2008-11-13 63 views
6

我想用一種特定的方法解析一個Apache access.log文件,儘管我對於面向對象編程是全新的,但我現在要開始做。從內建類繼承是否正確?

我要創建一個類ApacheAccessLog,我現在可以想像的唯一的事情,它會做的是「的readline」的方法。在這種情況下繼承文件類是否通常是正確的,因此該類將表現得類似文件類本身的實例,或者不是?這樣做的最好方法是什麼?

回答

15

在這種情況下,我會使用代表團而不是繼承。這意味着你的類應該包含文件對象作爲屬性,並在其上調用readline方法。您可以在記錄器類的構造函數中傳遞一個文件對象。

至少有兩方面的原因:

  1. 代表團在地方文件的對象,你可以用它實現了一個readline方法(鴨打字來得心應手這裏)任何其他對象減少耦合,例如。
  2. 從文件繼承時,類的公共接口變得不必要的寬泛。它包含文件中定義的所有方法,即使這些方法在Apache日誌中沒有意義。
1

從內置類繼承是完全可以接受的。在這種情況下,我會說你是對的。
日誌「是」文件,以便告訴您繼承是否正常。

一般規則。
狗「是一種」動物,因此繼承了動物。
所有者「有」n動物因此不從動物繼承。

1

雖然在某些情況下從內建繼承是有用的,但真正的問題在於您想要如何處理輸出以及您的大圖設計。我通常會寫一個閱讀器(使用一個文件對象)並吐出我需要的任何數據類來保存我剛剛閱讀的信息。那麼設計這個數據類就很容易,以適應我的其餘設計。

1

從「內建」類繼承,您應該相當安全,因爲後面對這些類的修改通常與當前版本兼容。

但是,您應該認真思考一下,您是否真的想將您的課程與內置課程提供的附加功能聯繫起來。正如在另一個答案中提到的,你應該考慮(或許更喜歡)代替代表

作爲避免繼承的一個例子,如果您不需要它,您可以查看java.util.Stack類。當它擴展Vector時,它繼承了Vector上方法的全部。這些方法中的大多數都打破了Stack所暗示的契約,例如,後進先出法。在內部使用Vector來實現Stack會更好,只會將Stack方法暴露爲API。然後很容易將實現更改爲ArrayList或稍後的其他東西,但由於繼承原因,現在沒有可能。

6

我來自Java的背景,但我相當相信,相同的原則將適用於Python。作爲一個經驗法則,你應該從來沒有繼承自你不明白和控制的實現類,除非該類是專門爲繼承而設計的。如果它是以這種方式設計的,它應該在文檔中清楚地說明這一點。

原因是繼承可能會將您綁定到您正在繼承的類的實現細節。

要使用從喬希布洛赫的書爲例「有效的Java」

如果我們爲了擴展類ArrayList類能算在其生命時間加入到它的項目的數量(不一定是它當前包含的數字),我們可能會試圖寫這樣的東西。

public class CountingList extends ArrayList { 
    int counter = 0; 

    public void add(Object o) { 
     counter++; 
     super.add(0); 
    } 

    public void addAll(Collection c) { 
     count += c.size(); 
     super.addAll(c); 
    } 

    // Etc. 
} 

現在這個擴展看起來像它會精確計算被添加到列表中的元素的數量,但實際上它可能不會。如果ArrayList已通過遍歷所提供的Collection並對其每個元素調用其接口方法addAll來實現addAll,那麼我們將統計通過addAll方法添加的每個元素兩次。現在我們班的行爲取決於ArrayList的實施細節。

這當然是除了不能使用List的其他實現與我們的CountingList類的缺點。加上從上面討論的具體類繼承的缺點。

我的理解是Python對Java使用類似的(如果不是相同的)方法調度機制,因此會受到相同的限制。如果有人能夠在Python中提供示例,我相信它會更有用。

0

你似乎已經找到了你的答案,在這種情況下,委派是更好的策略。儘管如此,我想補充一點,除了代表團之外,擴展內置類沒什麼問題,特別是如果您的替代方案取決於語言是「猴子修補程序」(參見http://en.wikipedia.org/wiki/Monkey_patch