2011-03-30 67 views
48

我通常會試圖確保我的對象實例符合Liskov Substitution Principle,但我一直在想,人們是否認爲LSP也適用於構造函數?施工人員是否應遵守Liskov替代原則?

我已經嘗試了谷歌搜索這個,但我一直沒能找到任何強烈的意見任何方式。

我應該注意到我的大部分代碼都是在Ruby中,但我有時會發現我的子類構造函數與父類稍有不同。他們採用相同的基本參數集,通常還有額外的參數。有時候,其他類方法也會發生這種情況。

在我的腦海裏,這總感覺像是違反了LSP,但我想看看是否有其他人也這樣認爲。

回答

50

不,當您使用構造函數時,您知道您正在處理子類型。這使您可以擁有父構造函數不需要的前提條件,例如其他參數。這就是爲什麼在大多數語言中,構造函數的名稱是創建類的名稱。

這是一個很好的例子,這是一個ColoredSquare可能是Square的適當子類型,但需要一個額外的參數:color。如果你不能做這樣的事情,那麼這些亞型的用處就會少得多。

從某種意義上講,構造函數並不是真正的類型的一部分:它是一個返回該類型元素的函數。因此,爲一個子類型定義一個新的構造函數不會破壞LSV。

+5

「當您使用構造函數時,您知道您正在處理子類型。」謝謝。這是一個很好的觀點。 – Chance 2011-05-25 15:28:06

+0

區分構造函數,靜態工廠方法,作爲正在生成的類型實例的工廠方法(最顯着的是'Clone')和其他工廠可能很重要。靜態工廠可能產生不同類型的從返回類型派生的對象,但LSP應該適用於所有產生的對象;但是,沒有要求,派生類支持與基類相同的靜態方法。如果一個類支持像Clone這樣的工廠方法,那麼應該遵循LSP並且支持子類型中的類似語義。 – supercat 2011-12-23 15:21:04

+0

對於返回其他類型的東西的工廠,從派生工廠返回的項目應該可用作從基本工廠返回的項目的實例。所以如果'CarFactory'有一個返回'Car'的'MakeCar()'方法,後者又支持'Drive()'方法,那麼應該可以調用'SomeCarFactory.MakeCar()。Drive()',即使'SomeCarFactory'實際上是一個'FordFactory'(繼承'CarFactory'),它返回一個'Ford'(繼承'Car')。 – supercat 2011-12-23 15:28:49

1

這是一種固執己見的問題,但我傾向於寫我的方式是這樣的,額外的參數對改變功能沒有真正的影響。我的意思是,當我的構造函數在子類中需要一個額外的參數時,它將保持標準功能(但是執行不同的底層事物),這樣可以說我創建了ClassA = new ClassB(帶有一些參數);那麼功能是相同的,無論我這樣做還是ClassA = new ClassA();我通常使用某種工廠方法來創建它們,所以它們在工作方式上是無縫的。這又是我如何做事,絕不是絕對正確的做事方式。

13

當然號

構造函數通常專門用於子類型。嘗試將LSP應用於構造函數就像說亞類不能添加特定的方法或成員。但限制只是另一種方式。我也同意菲利普,構造函數不是一個類型的一部分(在某些語言中,你可以很容易地使用其他工廠而不是構造函數)。使用smalltalk術語,你會說構造函數是元類的方法。

這裏沒有違反LSP,它只適用於實例方法,而不適用於類方法(構造函數或任何其他類方法)。