2012-10-02 76 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; 
    } 
}