2012-10-01 118 views
19

我有一個接口(移動),應該移動一些形狀。將接口擴展到抽象類

interface Move { move(); } 
abstract class Shape : Move 

class Circle : Shape 
class Square : Shape 
class Triangle : Shape 

我的疑問是,我必須有它移動的形狀,但只有圓形和三角形應該能夠移動的界面,讓我怎麼「刪除」,從廣場的界面?我應該從Shape中移除界面並在Circle和Triangle上手動添加它嗎?我有點困惑於此。希望有人能幫助我。

回答

34

,您應該設置你的類是這樣的:

interface IMovable { move(); } 
abstract class Shape : { } 

class Circle : Shape, IMovable { } 
class Square : Shape { } 
class Triangle : Shape, IMovable { } 

如果不是每一個形狀可以移動,然後Shape不得實現的接口。另外請注意,我將您的界面重命名爲IMovable,這不是什麼大問題,但它更受歡迎,而且命名規則更好。

+4

這個。 「如何不繼承一些基本行爲」這個問題的答案始終是「不要從一開始就繼承它」。 – KeithS

+0

@KeithS,這是正確的。停止繼承只是看待繼承的反面。所以,希望這會幫助OP認爲前進的另一種方式。 :) –

+4

@Mike,'IMovable'怎麼樣? – smartcaveman

27

您無法從繼承樹中刪除接口。

你模型似乎需要兩個抽象類 - ShapeMovableShape

interface IMove { move(); } 
abstract class Shape : {} 
abstract class MovableShape : IMove, Shape {} 

class Circle : MovableShape{} 
class Square : Shape{} 
class Triangle : MovableShape{} 
+3

這應該是公認的答案。 –

+3

@NadirSampaoli,你__opinion__得到足夠的重視,但要小心,因爲這會變成一個非常主觀的談話。有一點需要注意的是__I + 1也是這個答案,因爲它非常正確。 –

+3

@Mike我很抱歉,其實我的評論聽起來很大膽;我應該附加一個「在我看來」。 –

3

你應該讓自己更熟悉接口,類和麪向對象的概念。你要告訴的是以下內容:

  • 每個形狀都可以移動。
  • 正方形是一個形狀。
  • 但是Square不能移動。

有意思的是,這沒有意義。所以你必須調整你的課堂設計。可以移動每個形狀,Shape(和Square)應該實現Move,或者不移動每個形狀,然後Shape不應該實現Move。

3

嘗試了這一點:

interface IMove { move(); } 
abstract class Shape { } 

class Circle : Shape, IMove { } 
class Square : Shape { } 
class Triangle : Shape, IMove { } 
2

其他選項可能只是落實在ShapeIMove.Move方法,默認情況下拋出NotSupportedException。所以在一天結束時,「任何形狀都可以移動」,但「可移動的形狀應該提供它自己的如何移動它的實現」。

最後,我們假設有一堆形狀以相同的方式移動。你會創建一個DefaultMovableShape抽象類派生Shape,它會覆蓋Shape.Move虛擬方法。

public abstract class DefaultMovableShape 
{ 
    public override void Move() 
    { 
      // Do stuff 
    } 
} 
+0

雖然這可行,但我建議不要這樣做除非你的'Move'函數的規範明確地在界面層聲明'Move'會在它不適用於底層對象的情況下拋出一個異常。當然,在這一點上,您應該質疑爲什麼它實現了界面,並且您可能有設計問題(請參閱接受的答案)。 – Anthony

+0

@Anthony我同意了。我只是想給出一個選擇。我相信有理由認爲接受的答案是正確的做法,但是在某些情況下,我也可以完成這項工作。這取決於你如何看待問題:「形狀不可移動」或「形狀可移動」。 –

+0

@Anthony我仔細檢查了你的評論。這個聲明應該在'Shape'類文檔或'IMove'中。形狀「可能會移動」,因爲Shape可以提供「如何移動」的實現。所以如果你想移動一個無法移動的Shape,那麼這個Shape「不支持移動」。 –

2

最好的答案將取決於這些類的用例和環境。作爲開發應用程序或框架的團隊的一部分,採用該團隊使用的設計模式比尋求「完美」解決方案更可取,因爲它可以使其他人更容易採用和維護您的代碼。

您如何期待這些類的使用和擴展也很重要。你會期待'Square'在將來需要移動嗎?Shape的可移動性總是靜態的,或者它可能作爲動態屬性更有用? Move()對於不是Shapes的類有任何值嗎?如果可移動性的動態屬性是有用的,可以這樣考慮:

public abstract class Shape 
{ 
    public bool isMovable() 
    { 
     return false; 
    } 

    public virtual void Move() 
    { 
     if (!isMovable() { 
      throw new NotSupportedException(); 
     } else { 
      throw new BadSubclassException(); 
     } 
    } 
} 

你的子類可以然後覆蓋isMovable提供靜態或動態行爲,可以進一步修改或子類隨着時間的推移,只要你的文檔使清楚的是,移動應始終在移動的調用之前。默認行爲應基於您期望使用您的代碼的其他人的期望,這取決於他們如何實施相關設計模式。

作出這些決定的挑戰的一個很好的例子,可以通過查看如何集合類的易變性在不同的框架已經進化歷史中找到。已經有設計將可變類(集合,數組,字典等)作爲基類,在子類中實現了不變性,以及相反。有兩種方法,以及一個動態的方法有效參數,但對於一個框架,用戶最重要的因素是一致性,因爲什麼是正確的是真的,什麼是最簡單的事來使用,提供安全性能不會受到影響。