2012-02-05 63 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方法(如适用)和属性需要设置,当然:))

在这里,枚举工作在两种方式 - 其中一个实际上保存用于绘图的可用数据,另一个仅充当鉴别器。