1

我正处于游戏开发的早期阶段。这是某种回合制游戏,例如战锤或魔兽争霸。有些生物可以再生他们遭受的伤害并代表这一点我有一个这样的界面

public interface Regenerative {
    void regenerates();
}

所以再生的生物是

public class SomeMonster() extends BaseCreature implements Regeneative{
 //Code
 private int hitPoints;

 public void regenerates(){
  hitPoints = hitPoints + regenerateValue;
 }
}

我面临的问题是,并非所有生物都能再生相同数量的生命值,所以我必须将这个数量(regenerateValue)放在某个地方。因为我不能把它放在界面上(因为我不希望所有生物的数量都相同)我考虑在生物类中添加一个新属性

public class SomeMonster() extends BaseCreature implements Regeneative{
 //Code
 private int regenerateValue;

 public void regenerates(){
  hitPoints = hitPoints + regenerateValue;
 }
}

但我不喜欢这种方式(为什么不再生的生物的 regenerateValue 应该为 0?)。我认为它给了一个类不必要的属性,因此是一个糟糕的设计。您认为这种情况下最好的方法是什么?

4

7 回答 7

3

我面临的问题是,并非所有生物都能再生相同数量的生命值,所以我必须将这个数量(regenerateValue)放在某个地方。

为什么它必须是任何地方的字段?接口的某些实现可能对每个实例使用不同的值;其他人可能会使用一个常数值。

这是一个实现细节- 因此不适合接口。当然,您可以将它放在实现接口的抽象超类中。

知道界面的代码几乎肯定不应该知道或关心一个生物再生多少的细节 - 例如,它们可能根据魔法而不仅仅是生命值来再生,或者再生水平可能取决于其他一些功能他们的状态。来电者不应该在意。

于 2012-10-10T14:01:00.920 回答
2

我会将它添加到abstractBaseCreature 中,而不必太担心它。您的 BaseCreature 最终可能会得到许多实际上被“关闭”的属性,但另一种方法是创建一个复杂的继承树。由于 Java 不支持多重继承,这将阻碍您抽象出您可能喜欢的所有组合的能力。

于 2012-10-10T14:03:26.317 回答
1

如果所有怪物都再生,但其中一些再生值为 0(与不再生相同)怎么办?

所以你不需要接口:

public class SomeMonster() extends BaseCreature {
 //Code
    protected int regenerateValue; //protected, so that subclasses can override the value

    public void regenerates(){
        hitPoints = hitPoints + regenerateValue;
    }
}

regenerateValue 以 0 开头,因此您必须覆盖要实际重新生成的子类中的值

编辑删除“实现再生”

于 2012-10-10T14:05:56.287 回答
1

我认为您的设计可能没问题,因为您只需要在实现再生接口的类中包含一个 regenerateValue 即可。所以没有必要包含一个regenerateValue。

否则,您可以查看更复杂的设计模式,这些设计模式有利于组合而不是继承。通过这种方式,您可以在游戏期间为怪物动态添加再生能力以及其他“能力”,而不是每次需要更改怪物的行为时都必须重新编译游戏。

于 2012-10-10T14:08:43.917 回答
1

我使用的解决方案可能有点过度设计,但这允许很多扩展(再生,毒药,保护......)

我使用接口“CreatureProperties”,它定义了一个整数值和一个id,并且可以在每个回合对怪物执行操作。您将这些属性子类化以执行给定的属性

abstract class CreatureProperties {
   protected String id = "";
   protectd int propertyValue = 0;
   public void actOn(BaseMonster);
  // plus setter and getter
}

public RegenerationProperty implements CreatureProperties {
   final public REGENERATION_ID = "Regeneration";
   int regenerationValue = 0;

   public RegenerationProperty(int value){
      id = REGENERATION_ID;
      propertyValue= value;
   }

   public void actOn(BaseMonster monster){
      monster.setHitPoint(monster.getHitPoints()+propertyValue);
   }
}

in the BaseMonster class, you manage a set of MonsterProperty, initially empty.

    class BaseMonster {
       protected List<CreatureProperties> properties = 
         new ArrayList<CreatureProperties>();
       // plus management of propeties : add remove, iterator...

       public void update(){
          // perform all properties-linked update to monster
          foreach (CreatureProperty property : properties){
             property.actOn(this);
          }
       } 
    }

在 SomeMonster 的子类中,您只需在实例化期间添加此类怪物的一组属性。

class SomeMonster extends BaseMonster {
   public SomeMonster(){
      properties.add(new RegenerationProperty(5));  // presto : monster regenerate
   }
}

我在某些情况下使用 Id,其中每个刻度都没有使用该属性(即更新中没有任何内容),但例如减少伤害(id="LightningReduction"),或修改现有属性列表(一个属性删除所有再生属性并添加相同值的 PoisonProperty...)。

于 2012-10-10T16:10:11.133 回答
0

你可以在你的接口中添加一个方法,比如 getRegnerationValue(),确保所有具有该接口的生物都有这个方法来保存你想要使用的值或公式。

于 2012-10-10T14:00:46.823 回答
0

你应该问自己的问题是:如果一个生物应该再生,你怎么知道?它会实现不同的(或扩展的)基类吗?一种实现再生的?

如果答案是您将扩展基类(类似于 BaseRegeneratingCreature)并且所有再生生物都将扩展该类,那么这就是您的答案:BaseRegeneratingCreature 应该实现该接口,并具有再生所需的所有属性。

所有非再生生物都应该直接扩展 BaseCreature(或其他扩展类),并且不需要再生相关的属性。

然后,您的基类可能有一些方法,例如:

OnStartOfTurn();

这将在 BaseRegeneratingCreature 中调用 regenerates()(然后可能会调用 super()),并在 BaseCreature 中执行其他操作或调用其他方法。

于 2012-10-10T14:33:38.850 回答