2015-09-13 16 views
7

我有一個接口Polygon,然後我有一個類Quadrilateral。然後,我有兩個類,Square和Rectangle,它擴展了Quadrilateral。Square/Rectangle(帶約束不變式)之間的繼承關係共享Quadrilateral基底

四邊形由實例變量sideA,sideB,sideC和sideD組成。它包含方法area()和perimeter()來計算任何四邊形的面積和周長。

考慮到這一點,Square類有一個實例變量lengthOfSides,而Rectangle類有兩個實例變量,長度和寬度。由於四邊形中的方法面積和周長可以用於計算任何四邊形(包括正方形和矩形)的面積和周長,所以我認爲最好只是構造一個Square或Rectangle,然後調用超類分配邊(四邊形需要用於面積和周長計算)。另外,當Square或Rectangle中的實例變量發生變化時,設置器也會更新父類中的關聯值。

這裏是Square類:

/** 
* A model for a Square. 
* 
* @author BTKS 
*/ 
public class Square extends Quadrilateral { 

    private static final double ANGLES_SUM = 180; // the total sum of two opposite angles in degrees 

    private double lengthOfSides; // the length of each side 

    /** 
    * Construct a new Square. 
    * 
    * @param lengthOfSides the length of each side 
    */ 
    public Square(double lengthOfSides) { 
     super(ANGLES_SUM, lengthOfSides, lengthOfSides, lengthOfSides, lengthOfSides); 

     this.lengthOfSides = lengthOfSides; 
    } 

    /** 
    * @return the length of each side 
    */ 
    public double getLengthOfSides() { 
     return lengthOfSides; 
    } 

    /** 
    * @param lengthOfSides the length of each side 
    */ 
    public void setLengthOfSides(double lengthOfSides) { 
     this.lengthOfSides = lengthOfSides; 

     super.setSideA(lengthOfSides); 
     super.setSideB(lengthOfSides); 
     super.setSideC(lengthOfSides); 
     super.setSideD(lengthOfSides); 
    } 
} 

這被認爲是不好的做法?這是爲了一個大學的作業,她沒有具體說明她在找什麼。如果我不使用Square中的Quadrilateral中的任何東西,那麼擴展類Quadrilateral似乎是無用的。

+5

是的,這通常被認爲是不好的做法 - 但它有點爭議。問題的關鍵在於,如果你有一個Square實例並且調用mySquare.setSideA(newLength),將發生以下兩件事之一 - 或者你的方塊的邊長與其他邊的長度不一樣,或者邊B,C而D將「神奇地」設置爲其他值。我聽說要解決這個問題的經驗法則是,「平方值」(或不變的正方形)是「IS-A」四邊形值,但是「平方變量」(或可變正方形)不是IS-A四邊形變量。 –

+0

如果四邊形只有(抽象的)'getSide {N}'方法 - 但沒有'sideN'字段或設置器 - 那麼這將不是一個問題,因爲矩形/矩形不變量將被子類型中適當的'整形器'和'getSide {N}'訪問器將被適當地實現..但是如果它是抽象的,那麼不能創建一個真正的四邊形。 – user2864740

+0

那麼最好是隻覆蓋Square和Rectangle中的區域和邊界,而不是真的使用四邊形實例變量?我相信這個任務的目標是學習繼承和封裝,但這似乎不是學習它的最好例子。 –

回答

5

這取決於你想要在這裏表示「繼承」關係。通常,最好不要用所謂的「面向對象的繼承」來表示(事實上,我發現這種繼承的用處很少)。

在這種情況下,繼承關係似乎表達了這樣的事實,即子類相對於超類具有「附加約束」。如果多邊形是一類本身,而不是一個接口:

  • 多邊形(出現任何的,只要它是凸的)
  • 四邊形
  • 矩形(僅具有4個邊緣的附加約束)(附加的約束

    :具有π/ 2的角度)
  • 廣場(具有相同邊緣長度的附加約束)

基本上,我會的

或者只是編寫出Quadrilateral,刪除setters並使所有實例變量最終。這可以消除現象,即如果某人單獨更換雙方,就會在Square中獲得不受控制的更改。 (一般來說決賽是一個好主意)。然後子類減少爲只有特殊的構造函數。

或者只編程出Quadrilateral,不要繼承,給它布爾檢查:isRectangle(),isSquare(),也許離開setter。但這聽起來不太優雅。

也建議Bertrand Meyer的"The many faces of inheritance: a taxonomy of taxonomy"(1996)如果你能找到它,它會被支付,但可能有人在附近的IEEE Xplore訪問。

+0

我喜歡刪除setters和使所有實例變量最終的方法。謝謝! –

+0

我讀到[「一個小小的Java,一些模式」](https://mitpress.mit.edu/books/little-java-few-patterns)後,我開始儘可能地做最後的決定,它受到函數的嚴重影響語言傳統。一旦你注意到有多少戈爾登結在你這樣做的時候就會消失,你將永遠不會回頭(儘管垃圾收集器將不得不大量工作)。 –