2012-02-05 62 views
2

我在理解一些基本的OOP概念時遇到了問題。我會試着用一個例子來描述它。比方說,我有一個應用程序應該繪製不同形狀的圖形。如何在OOP中實現圖形層次結構

我創建一個圖類,並添加一個字段形狀(這是一種枚舉,可以是Shape.Circle或Shape.Square)。

public class Figure { 
    public Shape shape; 

    public void draw() { 
     if(shape == Shape.Square) 
      // draw a square 
     else if(shape == Shape.Circle) 
      // draw a circle 
    } 
} 

當我需要添加更多形狀到我的應用程序時,我必須添加更多ifs draw()方法。我認爲這很糟糕。

我可以使圖類的抽象(或使其成爲一個接口),從這個類繼承具體形狀的數字並重寫draw()方法。

public abstract Figure { void draw(); } 

public class Circle extends Figure { 
    @Override public void draw() { 
     // draw a circle 
    } 
} 

// same for Square 

當我需要新形狀時,我只是添加新的類。

接下來我決定爲自己的數字想要一個顏色:黑色或白色。黑色正方形和白色正方形應繪製不同。問題看起來一樣。我可以將Color字段添加到Figure類中,並在每個繪製方法中處理ifs或創建像BlackCircle,BlackSquare,WhiteCircle和WhiteSquare這樣的類。

如果我決定爲圖添加另一個屬性(比如說可以是小,中或大的大小),我必須創建2 * 2 * 3類,如BigBlackCircle,SmallWhiteSquare等等。而且我無法在運行時更改圖形的顏色或形狀。我認爲這不是正確的方法。

試圖瞭解問題,我發現我仍然可以爲所有數字單班。然後,我將顏色,形狀,大小作爲字段存儲並添加一種負責繪製的DisplayManager類。對於不同的繪圖算法,我可以有不同的DisplayManager實現。

public class Figure { 
    public Shape shape; 
    public Color color; 
    public Size size; 
    public DisplayManager display; 

    public void draw() { 
     display.draw(this); 
    } 
} 

public class DisplayManager { 
    public void draw(Figure figure) { 
     // drawing based on figure's shape, color and size 
    } 
} 

但是這樣我回到步驟1的問題:我不得不在draw()方法中處理很多ifs。任何人都可以在此解釋正確的方法嗎我應該如何設計這些類來保存我的應用程序的靈活性?

回答

3

代替聲明DisplayManager.draw(Figure),聲明Figure.draw(DisplayManager)。實施DisplayManager一些方法,以便它可以從Figure使用[drawPoint()的drawLine(),...]

併爲Figure每個擴展,實現自己的draw(DisplayManager)它使用給定DisplayManager

的具體實例
+0

謝謝。我在GoF的設計模式中找到了幾乎相同的解決方案。 – Soteric 2012-02-08 08:57:18

2

amit說的,你可以使用if語句或類的其他屬性來處理Square類的draw()方法中繪製黑色或白色方塊的不同方式。例如,你可以使用color屬性和枚舉屬性來枚舉Square的不同方法,並在draw()方法中處理它。

舉個例子,有大小的東西扔在顯示一個概念:

public abstract class Figure { 
    public enum Size { 
     SMALL(10), MEDIUM(20), LARGE(30); 

     private int actualSize; 

     private Size(int actualSize) { 
      this.actualSize = actualSize; 
     } 

     public int getActualSize() { 
      return actualSize; 
     } 
    } 

    public int x,y; 

    public Size size = Size.MEDIUM; 

    public Color color = Color.BLACK; 

    public abstract void draw(DisplayManager displayManager); 
} 

public class Square extends Figure { 
    public enum Corners { 
     SHARP, ROUNDED 
    } 

    public Corners corners = Corners.SHARP; 

    @Override 
    public void draw(DisplayManager displayManager) { 
     int s = size.getActualSize(); 
     displayManager.setColor(color); 

     switch (corners) { 
     case SHARP: 
      displayManager.drawBox(x-s, y-s, x+s, y+s); 
      break; 
     case ROUNDED: 
      displayManager.drawRoundedBox(x-s, y-s, x+s, y+s); 
      break; 
     } 
    } 
} 

(屬性公之於衆,以節省空間,使用專用的getter/setter方法(如適用)和屬性需要設置,當然:))

在這裏,枚舉工作在兩種方式 - 其中一個實際上保存用於繪圖的可用數據,另一個僅充當鑑別器。