2010-09-05 141 views
7

當我們從一個類繼承時,它可以提供場景嗎?它可以工作一段時間,但是其他的東西會改變並引入一個錯誤? 我想出了以下情況:從一個班級繼承以後會傷害你嗎?

  • 實現矩形有孔,我們從類Rectangle繼承。在構造函數中,我們檢查該洞是否在矩形內
  • 稍後有人添加一個Resize類到Rectangle的新方法。他們不檢查洞是否仍在裏面。
  • 經過調整大小後,我們可以在帶矩形孔的矩形孔中出現,這是一個錯誤。

如果我選擇在C#中使用對象繼承,我應該小心哪些其他問題。

+1

在C#中不需要小心,在任何面向對象的語言中都要小心。基類應該永遠不必擔心它們的後代。 – Robaticus 2010-09-05 16:11:29

+0

@Robaticus:我說C#是因爲在C++中我們可以繼承多個類,並且更容易陷入困境。在C#中,我們只能從一個類繼承。 – 2010-09-05 16:19:58

+0

我仍然支持我說的話。無論使用哪種語言,都應該注意這一點。它不是C#獨有的。 – Robaticus 2010-09-05 18:19:32

回答

5

對基類的改變會影響派生類的行爲有很多種方法。如果作者突然決定例如使類sealed怎麼辦?

像任何界面一樣,如果消費者不需要修改,它需要保持穩定。

繼承的主要「規則」是Liskov替換原則。這表明派生類應該可以替代基類或從它派生的其他類。

這種情況下,它的表面會破壞這條規則,因爲帶孔的矩形不是矩形。

通常最好使用接口將行爲劃分爲合理的可實現塊。這種界面通常用形容詞而不是名詞來命名。例如,矩形和帶有孔的矩形都可以被渲染,所以接口可能是IRenderable。如果它可以調整大小,你可能會有一個IResizable等等。這些可以彙總到一個IShape,但是你要小心你的Shape定義只定義了問題域中的行爲。

直接從另一個類派生可能會非常危險,因爲您受到該類行爲的約束。如果您真的需要這樣做,最好將您需要的實現提取到一個公共基類中(例如Rectangle : RectangleImplementation, IShape)。

6

你所描述的是繼承的缺陷之一。

另一個缺陷是深層繼承層次結構。在composition over inheritance上的Stackoverflow線程。

+0

希望我可以投這更多。 – 2010-09-05 16:05:52

0

不要在構造函數中調用虛方法。查看Eric Lippert的帖子(part 1part 2)。

3

這就是衆所周知的brittle base class problem

與一般的繼承另一個潛在的問題是,當你想用你自己的基本類,但一個框架需要特定的基類(例如,ContextBoundObject),而不是一個接口。

1

這就是爲什麼預測性的C#語言設計師將密封關鍵字添加到該語言。明智地使用。

並使用代碼合約來測試您的不變式以獲得有關破損的早期警告。

+0

Hans,你用什麼來表示「使用代碼契約來測試你的不變式以獲得關於破壞的早期警告」? – 2010-09-05 17:08:10

+0

鏈接:http://devjourney.com/blog/code-contracts-part-4-object-invariants/ – 2010-09-05 17:20:04

+0

不錯的鏈接,謝謝! – 2010-09-05 20:28:03

0

在這些類型的案例中更好地使用-Decorator模式。 這提供了更好的擴展方式。

這可以通過使用下面的圖來實現:alt text

矩形對象將被創建幷包裹成HoleDecorator對象,這將是負責提供的孔中。當完成Rectangle的大小調整時,將調用HoleDecorator的調整大小,這將首先調用Rectangle對象的Resize,然後調用Hole Decorator的AddedBehavior,它將指定當主要組件是調整大小。

+0

可以指定如何實現帶矩形的矩形? – 2010-09-05 17:10:47

0

我認爲這與c#或繼承無關。無論你做什麼,這都是軟件開發的必然問題。

最好的和簡單的解決方案是每天構建您的代碼並執行unit testing

+0

我們總是使用單元測試和配置項,但我不明白在這種情況下如何提供幫助。我們不針對尚不存在的情況創建單元測試。在開發之前,我們不可能有單元測試預測Resize方法。你能建議它是如何發生的嗎? – 2010-09-06 00:30:56

+0

單元測試通常會調用方法並比較輸入和輸出。我正在做類似問題的基於場景的單元測試。用你的榜樣;在創建了矩形後,將對象傳遞給Rectangle測試(執行調整大小,移動等)測試,並將其傳遞給具有相同上下文的Rectangle-With-Hole測試(執行邊界檢查)。這完全取決於開發人員的願景,而不是完美的,但有時比方法測試更好。順便說一句,它不是取代方法測試,它只是一個附加測試。 – ertan 2010-09-06 19:05:31

相關問題