Java 删除特定示例中的代码重复
我有三个重复代码的方法。 前两种方法几乎完全重复。第三个有点不同,因为对于火灾,应该绘制更多的信息 我想删除这个重复的代码,并考虑使用内部类的模板方法模式。这是正确的方法还是有更好的解决方案Java 删除特定示例中的代码重复,java,code-duplication,Java,Code Duplication,我有三个重复代码的方法。 前两种方法几乎完全重复。第三个有点不同,因为对于火灾,应该绘制更多的信息 我想删除这个重复的代码,并考虑使用内部类的模板方法模式。这是正确的方法还是有更好的解决方案 private void drawWaterSupplies(Graphics g) { double hScale = getWidth() / (double) groundMap.getWidth(); double vScale = getHeight() / (double) gr
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
}
}
在我看来,您收集的对象(
Fire
,WaterSupply
等)并不像它们应该的那样聪明。理想情况下,你应该能够说:
for (Fire f : groundMap.getFires()) {
f.draw(g);
}
而且每个对象都能够定位自身(使用其位置)、调整自身大小(因为火灾
知道将使用火灾图像
等)并将自身绘制到提供的图形对象上
为了更进一步,我希望将图形
对象传递给您的地图集,因此:
groundMap.drawFires(g);
其思想是,在OO中,您不应该询问对象的详细信息,然后再做出决策。相反,您应该告诉对象为您做一些事情。我将委托给另一个方法,并为火、水和能量创建一个超类。 这个超类将包含所有公共属性。例如
getLocation()
乙二醇
首先,似乎您可以有一个通用方法来接收
图形
、一个列表
和一个图像,以便第一个和第二个方法可以提取该列表并调用
第三种方法可以提取火灾列表,然后创建相应的列表
。然后使用新方法
private void drawImages(Graphics g, List<Location> where, Image imageToDraw) {
...
}
private void drawImages(图形g,列表位置,图像imageToDraw){
...
}
我认为一个简单的解决方案是使用一种方法并传递图形和位置集合。您可以使用一种方法
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());
}
private void drawImageAtLocations(图形g、图像图像、列表位置){
double hScale=getWidth()/(double)groundMap.getWidth();
double-vScale=getHeight()/(double)groundMap.getHeight();
int-imageOffsetX=image.getWidth()/2;
int-imageOffsetY=image.getHeight()/2;
对于(位置l:位置){
intx=(int)(l.getX()*hScale);
int y=(int)(l.getY()*vScale);
g、 drawImage(image,x-imageOffsetX,y-imageOffsetY,null);
}
}
专用排水系统(图g){
drawImageAtLocations(g,waterSupplyImage,groundMap.getWaterSupplyLocations());
}
那么:
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);
}
}
第三个有点混乱,但仍然比原来的要短:
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
Set derp=new HashSet();
对于(Fire-Fire:groundMap.getFires())derp.add(Fire.getLocation());
drawImageAtLocations(g、fireImage、derp);
//drawImageAtLocations(g、fireStatusBarImage、derp);//托多废话
这就是我的主张
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);
}
}
。。。。
你们可以在地图>(Map>)中保存火、水、能源等的所有位置,所以方法getLocations(supply)或多或少是这样的
List<Location> getLocations(Supplies supply)
{
return supplyMap.get(supply);
}
列出地点(供应品)
{
返回supplyMap.get(supply);
}
如果您想添加或删除供应品和事故,此解决方案为您提供了更大的灵活性这不是最短的选择,但它使代码更干净,更易于扩展:
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;
}
}
enum YourEnum{
水,,
能量
火;
}
私有void draw(图形g,YourEnum类型){
位图位图=getRightBitmap(类型);
double hScale=getWidth()/(double)groundMap.getWidth();
double-vScale=getHeight()/(double)groundMap.getHeight();
int imageOffsetX=bitmap.getWidth()/2;
int-imageOffsetY=bitmap.getHeight()/2;
对于(位置l:getLocations(类型)){
intx=(int)(l.getX()*hScale);
int y=(int)(l.getY()*vScale);
g、 drawImage(位图,x-imageOffsetX,y-imageOffsetX,
无效);
}
}
私有位图getRightBitmap(您的枚举类型){
开关(类型){
案例水:
返回水源图像;
案例能量:
返回水源图像;
案例火灾:
返回图像;
}
}
私有集合getLocations(YourEnum类型){
开关(类型){
案例水:
返回groundMap.getWaterSupplyLocations();
案例能量:
返回groundMap.getEnergySupCollections();
案例火灾:
集合位置=新的ArrayList();
for(Fire-Fire:groundMap.getFires()){
add(fire.getLocation());
}
返回地点;
}
}
不应该是列表吗?我也考虑过这一点,但对于火灾,应该绘制更多其他位置不可用的信息。抱歉,如果这不清楚,我编辑了我的问题。看起来不错。但这不违反了模型和表示的分离吗?@kobo-有趣的一点。为了完全实现这种分离,我想你必须研究双重分派/访问者模式,比如Fire对象(比如)和图形目的地在它们之间进行调解,以确定它们需要实现什么drawingokay,我试图弄清楚这是如何工作的。我会有一个带有方法的访问者界面:visit(firef)
,visit(WaterSupply w)
。。。然后,对于绘图,我将有一个新的DrawingVisitor(Graphics g)
,它实现了访问者界面来绘制对象。这就是你刚才说的吗?
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);
}
}
List<Location> getLocations(Supplies supply)
{
return supplyMap.get(supply);
}
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;
}
}