在特定示例中删除代码重复

时间:2012-10-02 13:02:32

标签: java code-duplication

我有三种重复代码的方法。 前两种方法几乎完全重复。第三个与火灾略有不同,应该绘制更多的信息。

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

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
    }
}

8 个答案:

答案 0 :(得分:5)

在我看来,你的对象集合(FireWaterSupply等)并不像它们应该的那样聪明。理想情况下,您应该能够说:

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

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

为了更进一步,我希望将Graphics对象传递给你的groundMap:

groundMap.drawFires(g);

这个想法是在OO中你不应该向对象询问他们的细节然后做出决定。 相反,你应该告诉对象为你做事

答案 1 :(得分: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()) {

答案 2 :(得分: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

答案 3 :(得分:0)

首先,您似乎可以拥有一个接收GraphicsList<Location>和图像的常用方法,因此第一个和第二个方法可以提取该列表并进行调用。

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

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

答案 4 :(得分:0)

我认为一个简单的解决方案是使用一个方法并传递Graphics和Location的集合。

答案 5 :(得分: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());
}

答案 6 :(得分: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);
    }
}

.... 您可以在地图&gt;中保存的所有火灾,水,能源等位置,因此方法getLocations(供应)或多或少看起来像那样

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

如果您想添加或删除耗材和事故,此解决方案可为您提供更大的灵活性

答案 7 :(得分: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;
    }
}