干燥Java代码的最佳方法是什么?为参数创建具有不同对象的私有方法?

干燥Java代码的最佳方法是什么?为参数创建具有不同对象的私有方法?,java,dry,code-cleanup,Java,Dry,Code Cleanup,我正在制作一个RTS游戏,其中一个特点是建造不同类型的建筑。我发现了很多重复,我想用helper方法来提取它,但问题是每栋建筑都是不同的对象,它从主建筑类继承了一些属性yes 构建方法如下所示: public static void buildDockyard(Base base) { if (Validator.checkForBuilding(base, "Dockyard")) { throw new IllegalStateException

我正在制作一个RTS游戏,其中一个特点是建造不同类型的建筑。我发现了很多重复,我想用helper方法来提取它,但问题是每栋建筑都是不同的对象,它从主建筑类继承了一些属性yes

构建方法如下所示:

  public static void buildDockyard(Base base) {
    if (Validator.checkForBuilding(base, "Dockyard")) {
       throw new IllegalStateException("Dockyard is already build");
     }
    Dockyard dockyard = new Dockyard("Dockyard");
    int requiredPower = dockyard.requiredResource("power");
    int requiredStardust = dockyard.requiredResource("stardust");
    int requiredPopulation = dockyard.requiredResource("population");

    Validator.checkResource(base, requiredPower, requiredStardust, requiredPopulation);
    updateResourceAfterBuild(base, requiredPower, requiredStardust, requiredPopulation);
    dockyard.setCompleteTime(dockyard.requiredResource("time"));
    base.getBuildings().add(dockyard);
  }

  public static void buildHotel(Base base) {
    if (Validator.checkForBuilding(base, "Space Hotel")) {
      throw new IllegalStateException("Space Hotel is already build");
    }

    SpaceHotel spaceHotel = new SpaceHotel("Space Hotel");
    int requiredPower = spaceHotel.requiredResource("power");
    int requiredStardust = spaceHotel.requiredResource("stardust");
    int requiredPopulation = spaceHotel.requiredResource("population");

    Validator.checkResource(base, requiredPower, requiredStardust, requiredPopulation);
    updateResourceAfterBuild(base, requiredPower, requiredStardust, requiredPopulation);
    spaceHotel.setCompleteTime(spaceHotel.requiredResource("time"));
    base.getBuildings().add(spaceHotel);

    base.setCapacity(base.getCapacity() + spaceHotel.getCapacity());
  }
if (getBuildings().contains(structure)) {
   throw new IllegalStateException(structure.name + " is already build");
}
if (validateStillHaveEnoughResourcesFor(structure)) {
   throw new IllegalStateException(structure.name + " can not be added. Not enough resources");
}
getBuildings().add(structure);
public static void someFunction(Base base, Object param1, Object param2)
public static void someOtherFunc(Base base, Object paramA, Object paramB)
...
public abstract class Building {
    private ... cost;
    private ... requirements;
    private ... 

    // Std-Getter and Setter methods
    public ... getCost() { return this.cost; }

}
我在考虑这样重构: 辅助方法

private static void construct(Building building, Base base) {
    int requiredPower = building.requiredResource("power");
    int requiredStardust = building.requiredResource("stardust");
    int requiredPopulation = building.requiredResource("population");

    Validator.checkResource(base, requiredPower, requiredStardust, requiredPopulation);
    updateResourceAfterBuild(base, requiredPower, requiredStardust, requiredPopulation);
    building.setCompleteTime(building.requiredResource("time"));
  }
目标结果

public static void buildDockyard(Base base) {
        if (Validator.checkForBuilding(base, "Dockyard")) {
           throw new IllegalStateException("Dockyard is already build");
         }
        Dockyard dockyard = new Dockyard("Dockyard");
        construct(dockyar, base);
        base.getBuildings().add(dockyard);
      }
问题是每个建筑都有独特的属性和资源需求,而主建筑类不知道它们,所以我不能在helper方法中将其用作参数

所有这些都发生在基类的静态助手类中

您将如何重构此代码?
提前谢谢你

你的问题是从使用静态方法开始的。在一个面向对象的世界中,理想情况下,你有一个对象库,它会有一个非静态的方法AddStructureStructure,例如,如果structure是一个接口的话。现在,您将拥有像Building和Dockyard这样的对象,它们将实现结构

addStructure的实现如下:

  public static void buildDockyard(Base base) {
    if (Validator.checkForBuilding(base, "Dockyard")) {
       throw new IllegalStateException("Dockyard is already build");
     }
    Dockyard dockyard = new Dockyard("Dockyard");
    int requiredPower = dockyard.requiredResource("power");
    int requiredStardust = dockyard.requiredResource("stardust");
    int requiredPopulation = dockyard.requiredResource("population");

    Validator.checkResource(base, requiredPower, requiredStardust, requiredPopulation);
    updateResourceAfterBuild(base, requiredPower, requiredStardust, requiredPopulation);
    dockyard.setCompleteTime(dockyard.requiredResource("time"));
    base.getBuildings().add(dockyard);
  }

  public static void buildHotel(Base base) {
    if (Validator.checkForBuilding(base, "Space Hotel")) {
      throw new IllegalStateException("Space Hotel is already build");
    }

    SpaceHotel spaceHotel = new SpaceHotel("Space Hotel");
    int requiredPower = spaceHotel.requiredResource("power");
    int requiredStardust = spaceHotel.requiredResource("stardust");
    int requiredPopulation = spaceHotel.requiredResource("population");

    Validator.checkResource(base, requiredPower, requiredStardust, requiredPopulation);
    updateResourceAfterBuild(base, requiredPower, requiredStardust, requiredPopulation);
    spaceHotel.setCompleteTime(spaceHotel.requiredResource("time"));
    base.getBuildings().add(spaceHotel);

    base.setCapacity(base.getCapacity() + spaceHotel.getCapacity());
  }
if (getBuildings().contains(structure)) {
   throw new IllegalStateException(structure.name + " is already build");
}
if (validateStillHaveEnoughResourcesFor(structure)) {
   throw new IllegalStateException(structure.name + " can not be added. Not enough resources");
}
getBuildings().add(structure);
public static void someFunction(Base base, Object param1, Object param2)
public static void someOtherFunc(Base base, Object paramA, Object paramB)
...
public abstract class Building {
    private ... cost;
    private ... requirements;
    private ... 

    // Std-Getter and Setter methods
    public ... getCost() { return this.cost; }

}

验证结构本身不应位于基础中。验证结构与基础的匹配程度应该在基础中。

制作游戏时,用Java干燥的最佳方法是对游戏有一个清晰的理解和术语。如果你阅读任何一本现代棋盘游戏手册,你很快就会发现他们会用一个词来表示一个概念,比如转身、转身、建筑、玩家、资源。这样就可以形成一个粗略的结构:一座建筑需要一定数量的资源。如果一个玩家没有足够的资源,那么告诉他我们需要更多的vespine气体等等。图片越清晰,你的Java就越枯燥,为你的代码创建必要的类就越容易

参数

如果你的结局是这样的:

  public static void buildDockyard(Base base) {
    if (Validator.checkForBuilding(base, "Dockyard")) {
       throw new IllegalStateException("Dockyard is already build");
     }
    Dockyard dockyard = new Dockyard("Dockyard");
    int requiredPower = dockyard.requiredResource("power");
    int requiredStardust = dockyard.requiredResource("stardust");
    int requiredPopulation = dockyard.requiredResource("population");

    Validator.checkResource(base, requiredPower, requiredStardust, requiredPopulation);
    updateResourceAfterBuild(base, requiredPower, requiredStardust, requiredPopulation);
    dockyard.setCompleteTime(dockyard.requiredResource("time"));
    base.getBuildings().add(dockyard);
  }

  public static void buildHotel(Base base) {
    if (Validator.checkForBuilding(base, "Space Hotel")) {
      throw new IllegalStateException("Space Hotel is already build");
    }

    SpaceHotel spaceHotel = new SpaceHotel("Space Hotel");
    int requiredPower = spaceHotel.requiredResource("power");
    int requiredStardust = spaceHotel.requiredResource("stardust");
    int requiredPopulation = spaceHotel.requiredResource("population");

    Validator.checkResource(base, requiredPower, requiredStardust, requiredPopulation);
    updateResourceAfterBuild(base, requiredPower, requiredStardust, requiredPopulation);
    spaceHotel.setCompleteTime(spaceHotel.requiredResource("time"));
    base.getBuildings().add(spaceHotel);

    base.setCapacity(base.getCapacity() + spaceHotel.getCapacity());
  }
if (getBuildings().contains(structure)) {
   throw new IllegalStateException(structure.name + " is already build");
}
if (validateStillHaveEnoughResourcesFor(structure)) {
   throw new IllegalStateException(structure.name + " can not be added. Not enough resources");
}
getBuildings().add(structure);
public static void someFunction(Base base, Object param1, Object param2)
public static void someOtherFunc(Base base, Object paramA, Object paramB)
...
public abstract class Building {
    private ... cost;
    private ... requirements;
    private ... 

    // Std-Getter and Setter methods
    public ... getCost() { return this.cost; }

}
这是一个强烈的暗示,可能两个函数都应该是基类的一部分

列举

如果您有一组有限的值,那么Java枚举可以很好地表示它们,例如,您的资源系统:

public enum Resource {
    POWER, STARDUST, POPULATION
}
现在你不必记得你是否称之为星尘,星尘,或者你是否还有像星尘这样的资源。相反,您可以使用int requiredPower=building.requiredResource.POWER

多态性

假设我们有两个类,Building和StarHotel,StarHotel是一种特殊的建筑。通过抽象类构建,我们可以以特定的方式处理一些通用机制,如下所示:

  public static void buildDockyard(Base base) {
    if (Validator.checkForBuilding(base, "Dockyard")) {
       throw new IllegalStateException("Dockyard is already build");
     }
    Dockyard dockyard = new Dockyard("Dockyard");
    int requiredPower = dockyard.requiredResource("power");
    int requiredStardust = dockyard.requiredResource("stardust");
    int requiredPopulation = dockyard.requiredResource("population");

    Validator.checkResource(base, requiredPower, requiredStardust, requiredPopulation);
    updateResourceAfterBuild(base, requiredPower, requiredStardust, requiredPopulation);
    dockyard.setCompleteTime(dockyard.requiredResource("time"));
    base.getBuildings().add(dockyard);
  }

  public static void buildHotel(Base base) {
    if (Validator.checkForBuilding(base, "Space Hotel")) {
      throw new IllegalStateException("Space Hotel is already build");
    }

    SpaceHotel spaceHotel = new SpaceHotel("Space Hotel");
    int requiredPower = spaceHotel.requiredResource("power");
    int requiredStardust = spaceHotel.requiredResource("stardust");
    int requiredPopulation = spaceHotel.requiredResource("population");

    Validator.checkResource(base, requiredPower, requiredStardust, requiredPopulation);
    updateResourceAfterBuild(base, requiredPower, requiredStardust, requiredPopulation);
    spaceHotel.setCompleteTime(spaceHotel.requiredResource("time"));
    base.getBuildings().add(spaceHotel);

    base.setCapacity(base.getCapacity() + spaceHotel.getCapacity());
  }
if (getBuildings().contains(structure)) {
   throw new IllegalStateException(structure.name + " is already build");
}
if (validateStillHaveEnoughResourcesFor(structure)) {
   throw new IllegalStateException(structure.name + " can not be added. Not enough resources");
}
getBuildings().add(structure);
public static void someFunction(Base base, Object param1, Object param2)
public static void someOtherFunc(Base base, Object paramA, Object paramB)
...
public abstract class Building {
    private ... cost;
    private ... requirements;
    private ... 

    // Std-Getter and Setter methods
    public ... getCost() { return this.cost; }

}
每栋建筑都有成本、需求和其他重要变量。但是我们处理了所有获取这些通用变量并将其设置为基类的标准工作,现在我们可以从中扩展其他更具体的建筑。由于extends关键字,您可以获得StarHotel对象的成本,而无需使用重复的getter和setter填充StarHotel类

public class StarHotel extends Building {
    // Getter, Setter inherited from Building class
}
接口

Java接口允许您定义定义方法的接口。外行术语:这很有用,因为实现接口的每个类都必须实现方法,除非接口提供默认实现

public interface ResourceProvider {
    void provideResourceFor(Base base); // A Resource Provider provides Resource for a base.
}
通过这个接口,我们定义了如果某个类实现ResourceProvider,它必须指定如何以及为某个基本对象提供哪些资源。我们的接口并不关心哪种资源、哪种基础、甚至ProviderSourceFor可能意味着什么,但只要某个东西实现了ResourceProvider,它就必须提供功能

综合

将枚举、接口和多态性放在一起,我们现在可以创建一个StarHotel类来扩展构建并实现ResourceProvider,为我们的基础提供8个食物单位和2个快乐单位

public class StarHotel extends Building implements ResourceProvider
    public void provideResourceFor(Base base) {
        base.addResource(Resource.FOOD, 8);
        base.addResource(Resource.HAPPINESS, 2);
    }
}

这可能是一个需要考虑的问题,但希望它能为您提供一个好的方向,让您进一步了解。

给您一个起点:为什么您需要提取所需的资源来分别将它们传递给验证器?如果验证器可以直接处理建筑,不是更容易吗?当验证器只检查所需的资源是否在base中可用时,为什么验证器会自己检查呢?无法要求给定的建筑说明可用资源是否足够?谢谢!我忘了提到,所有这些都发生在基类的helper类中,这就是为什么所有方法都是静态的,与验证器相同很多验证都在进行:D@Ili这不是使方法静态的好理由。并不是说他们不需要,但给出的理由本身并不是做出这种设计决策的好理由。塔莫提出的观点不仅有效,而且可能与你的问题直接相关。你应该考虑重新审视你的决定,也许遵循他的建议。
特别是,如果这些帮助器类被用来存储数据的话。非常详细的解释!向上投票。