2012-10-02 47 views
3

我有三种重复代码的方法。 前两种方法几乎完全重复。第三种情况与火灾有所不同,应该提供更多信息。删除特定示例中的代码重复

我想删除这个重复的代码,并考虑使用内部类的模板方法模式。这是正确的方式还是有更好的解决方案?

private void drawWaterSupplies(Graphics g) { 
    double hScale = getWidth()/(double) groundMap.getWidth(); 
    double vScale = getHeight()/(double) groundMap.getHeight(); 

    int imageOffsetX = waterSupplyImage.getWidth()/2; 
    int imageOffsetY = waterSupplyImage.getHeight()/2; 
    for (Location l : groundMap.getWaterSupplyLocations()) { 
     int x = (int) (l.getX() * hScale); 
     int y = (int) (l.getY() * vScale); 

     g.drawImage(waterSupplyImage, x - imageOffsetX, y - imageOffsetY, 
       null); 
    } 
} 

private void drawEnergySupplies(Graphics g) { 
    double hScale = getWidth()/(double) groundMap.getWidth(); 
    double vScale = getHeight()/(double) groundMap.getHeight(); 

    int imageOffsetX = energySupplyImage.getWidth()/2; 
    int imageOffsetY = energySupplyImage.getHeight()/2; 
    for (Location l : groundMap.getEnergySupplyLocations()) { 
     int x = (int) (l.getX() * hScale); 
     int y = (int) (l.getY() * vScale); 

     g.drawImage(energySupplyImage, x - imageOffsetX, y - imageOffsetY, 
       null); 
    } 
} 

private void drawFires(Graphics g) { 
    double hScale = getWidth()/(double) groundMap.getWidth(); 
    double vScale = getHeight()/(double) groundMap.getHeight(); 

    int imageOffsetX = fireImage.getWidth()/2; 
    int imageOffsetY = fireImage.getHeight()/2; 
    for (Fire fire : groundMap.getFires()) { 
     Location l = fire.getLocation(); 
     int x = (int) (l.getX() * hScale); 
     int y = (int) (l.getY() * vScale); 

     g.drawImage(fireImage, x - imageOffsetX, y - imageOffsetY, null); 
     // TODO: draw status bar showing state of fire below 
    } 
} 

回答

5

在我看来,你的对象的集合(FireWaterSupply等)不聪明,因为他们应该的。理想情况下,你应该能够说:

for (Fire f : groundMap.getFires()) { 
    f.draw(g); 
} 

每个对象将能够(使用它的位置)来定位自己,本身的大小(因为Fire知道它会使用FireImage等),并绘制自身到提供的Graphics对象。

为了进一步借此,我希望到Graphics对象传递给你的groundMap这样的:

groundMap.drawFires(g); 

的想法是,在面向对象的,你不应该问他们细节的对象,然后做出决定。 相反,你应该告诉物体为你做事

+0

看起来不错。但是这不违反模型和表示的分离吗? – kobo

+0

@ kobo - 有趣的一点。为了完全实现这种分离,我想你必须调查双重发送/访问者模式,例如Fire对象(比如说)和图形目标在它们自己之间进行调解以达到他们需要实现的图形 –

+0

好吧,我试过了弄清楚这是如何工作的。 我会有一个访问接口的方法:'访问(Fire f)','访问(WaterSupply w)',... 然后,对于绘图,我将有一个'新的DrawingVisitor(Graphics g)',它实现访客界面来绘制对象。 这是不是你在说什么? – kobo

1

我将委托给另一种方法,并创建一个火,水和能源的超级类。 这个超类会隐藏所有常见的属性。例如getLocation()

private void drawEverything(Graphics g, Image im, List<? extends SuperClassOfFireEtc> list, double w, double h) { 
    double hScale = getWidth()/w; 
    double vScale = getHeight()/h; 

    int imageOffsetX = im.getWidth()/2; 
    int imageOffsetY = im.getHeight()/2; 
    for (SuperClassOfFireEtc f : list) { 
     Location l = f.getLocation(); 
     int x = (int) (l.getX() * hScale); 
     int y = (int) (l.getY() * vScale); 

     g.drawImage(im, x - imageOffsetX, y - imageOffsetY, null); 
    } 

}

然后drawFire可以调用

private void drawEverything(g, fireImage, groundMap.getFires(), groundMap.getWidth(), groundMap.getHeight()) { 
+1

不应该是'List <?由于协变性而扩展SuperClassOfFireEtc>? – halex

+0

是的,你是正确的@halex – RNJ

+0

我也想过这个,但对于火灾,应该绘制更多的信息,这些信息不适用于其他位置。对不起,如果这是不明确的,我编辑我的问题。 – kobo

0

首先,它似乎你可以有接收Graphics,一个List<Location>的常用方法和图像,以第一第二种方法可以提取该列表并调用。

第三种方法可以提取Fire的列表,然后创建相应的List<Location>。然后使用新的方法。

private void drawImages(Graphics g, List<Location> where, Image imageToDraw) { 
... 
} 
0

我认为一个简单的解决方案是有一个方法,并传递图形和位置的集合。

0

你可以有一个方法。

private void drawImageAtLocations(Graphics g, Image image, List<Location> locations) { 
    double hScale = getWidth()/(double) groundMap.getWidth(); 
    double vScale = getHeight()/(double) groundMap.getHeight(); 

    int imageOffsetX = image.getWidth()/2; 
    int imageOffsetY = image.getHeight()/2; 
    for (Location l : locations) { 
     int x = (int) (l.getX() * hScale); 
     int y = (int) (l.getY() * vScale); 

     g.drawImage(image, x - imageOffsetX, y - imageOffsetY, null); 
    } 
} 

private void drawWaterSupplies(Graphics g) { 
    drawImageAtLocations(g, waterSupplyImage, groundMap.getWaterSupplyLocations()); 
} 
1

如何:

private void drawImageAtLocations(Graphics g, Image i, Collection<Location> cl) { 
    double hScale = getWidth()/(double) groundMap.getWidth(); 
    double vScale = getHeight()/(double) groundMap.getHeight(); 

    int imageOffsetX = i.getWidth()/2; 
    int imageOffsetY = i.getHeight()/2; 
    for (Location l : cl) { 
     int x = (int) (l.getX() * hScale); 
     int y = (int) (l.getY() * vScale); 

     g.drawImage(i, x - imageOffsetX, y - imageOffsetY, null); 
    } 
} 

工程右出前两个盒子:

drawImageAtLocations(g, waterSupplyImage, groundMap.getWaterSupplyLocations()); 
drawImageAtLocations(g, energySupplyImage, groundMap.getEnergySupplyLocations()); 

第三个是有点混乱,但仍小于什么是最初有:

Set<Location> derp = new HashSet<Location>(); 
for (Fire fire : groundMap.getFires()) derp.add(fire.getLocation()); 
drawImageAtLocations(g, fireImage, derp); 
// drawImageAtLocations(g, fireStatusBarImage, derp); // TODO blah blah 
0

和这就是我主张

enum Supplies {FIRE(fireImage), WATER(waterImage), ENERGY(energyImage); 
private Bitmap image; 
Supplies(Bitmap image) 
{ 
    this.image = image 
} 

public getImage() 
{ 
    return image; 
} 

} 

private void draw(Graphics g,Supplies supply) { 
    double hScale = getWidth()/(double) groundMap.getWidth(); 
    double vScale = getHeight()/(double) groundMap.getHeight(); 

    int imageOffsetX = supply.getImage.getWidth()/2; 
    int imageOffsetY = supply.getImage.getHeight()/2; 
    for (Location location : groundMap.getLocations(supply)) { 

     int x = (int) (location .getX() * hScale); 
     int y = (int) (location .getY() * vScale); 

     g.drawImage(supply.getImage, x - imageOffsetX, y - imageOffsetY, null); 
    } 
} 

.... 所有位置火,水,能源等您还可以在地图举行>,所以方法的getLocations(供应)会或多或少地样子说

List<Location> getLocations(Supplies supply) 
{ 
return supplyMap.get(supply); 
} 

,如果你想添加或删除用品和事故

0

不是最短的替代,但它使代码更干净,更容易扩展该解决方案为您提供了更多的灵活性:

enum YourEnum { 
    WATER, 
    ENERGY, 
    FIRE; 
} 

private void draw(Graphics g, YourEnum type) { 
    Bitmap bitmap = getRightBitmap(type); 
    double hScale = getWidth()/(double)groundMap.getWidth(); 
    double vScale = getHeight()/(double)groundMap.getHeight(); 

    int imageOffsetX = bitmap.getWidth()/2; 
    int imageOffsetY = bitmap.getHeight()/2; 
    for (Location l : getLocations(type)) { 
     int x = (int)(l.getX() * hScale); 
     int y = (int)(l.getY() * vScale); 

     g.drawImage(bitmap, x - imageOffsetX, y - imageOffsetY, 
       null); 
    } 
} 



private Bitmap getRightBitmap(YourEnum type) { 
    switch (type) { 
     case WATER: 
      return waterSupplyImage; 
     case ENERGY: 
      return waterSupplyImage; 
     case FIRE: 
      return fireImage; 
    } 
} 

private Collection<Location> getLocations(YourEnum type) { 
    switch (type) { 
     case WATER: 
      return groundMap.getWaterSupplyLocations(); 
     case ENERGY: 
      return groundMap.getEnergySupCollections(); 
     case FIRE: 
      Collection<Location> locations = new ArrayList<Location>(); 
      for (Fire fire : groundMap.getFires()) { 
       locations.add(fire.getLocation()); 
      } 
      return locations; 
    } 
}