2012-01-23 110 views
4

其中一個recommended principles of object-oriented programmingLiskov substitution principle:子類的行爲應與其基類相同(警告:實際上這不是Liskov原理的正確描述:請參閱PS)。類繼承:構造函數應該兼容嗎?多重繼承的情況?

是否建議它也適用於構造函數?我主要考慮Python和它的__init__()方法,但這個問題適用於任何具有繼承的面嚮對象語言。

我在問這個問題,因爲有一個子類繼承一個或多個提供一些很好的默認行爲的類是有用的(就像在Python中從字典繼承,所以obj['key']適用於新類的對象)。然而,讓子類完全像字典一樣使用並不總是自然的或簡單的:有時更好的是構造函數參數只與特定的用戶子類相關(例如,代表一組串行端口的類可能想要像ports['usb1']作爲USB端口#1的字典那樣)。對於這種情況推薦的方法是什麼?具有與其基類完全兼容的子類構造函數,並通過一個對象工廠函數生成實例,該函數採用簡單的,用戶友好的參數?或者簡單地寫一個類構造函數,它的參數集不能直接賦給它的基類的構造函數,但是從用戶的角度來看更合理?

PS:我曲解了Liskov的原則,上面:下面斯文的評論指出一個事實,即對象子類的應該表現得像超(子類本身並沒有表現得像超類的對象;特別是它們的構造函數不必具有相同的參數[簽名])。

+1

@SvenMarnach:你的評論應該是被接受的答案。 –

+0

@SvenMarnach:+1:確實如此。如果你寫一個答案,我會很樂意提出你的答案(請做!)。當你回答我的一個主要問題時,我也可以將其標記爲已被接受。 – EOL

回答

4

根據要求,我發佈了一個答案以前的評論。

在鏈接的維基百科文章中定義的原則是「如果S是T的子類型,那麼類型T的對象可以用類型S的對象替換」。它不會讀「一個子類的行爲應該和它的基類相同」。考慮構造函數時,區別很重要:維基百科版本只討論子類型的對象,而不是類型本身。對於一個對象來說,構造函數已經被調用,所以這個原則不適用於構造函數。這也是我應用它的方式,以及它在標準庫中應用的方式(例如,defaultdictdict)。

多重繼承中的構造函數可能無法用與語言無關的方式進行討論。在Python中,有兩種方法。如果您的繼承關係圖包含菱形圖案,並且您需要確保所有構造函數只被調用一次,則應使用super()並遵循Raymond Hettinger的文章Python's super() considered super中的「實用建議」一節中所述的模式。如果你沒有鑽石(除了包括object),你也可以對所有基類構造函數使用明確的基類調用。