在哪里放置一个接口相关的变量,它不是静态的和最终的

时间:2012-10-10 13:58:28

标签: java interface

我处于游戏开发的早期阶段。这是一种像战锤或魔兽一样的回合制游戏。有些生物可以重生他们遭受的伤害并代表我有这样的界面

public interface Regenerative {
    void regenerates();
}

所以再生的生物是

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

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

我面临的问题是,并非所有生物都会重生相同的生命值,因此我必须将该数量(regenerateValue)放置在某处。因为我不能把它放在界面上(因为我不希望ammount与所有生物相同)我曾想过在生物类中添加一个新属性

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

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

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

7 个答案:

答案 0 :(得分:3)

  

我面临的问题是并非所有生物都会重生相同数量的生命值,因此我必须将该数量(regenerateValue)放置在某处。

为什么它必须是字段?接口的某些实现可能会为每个实例使用不同的值;其他人可能会使用一个恒定值。

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

了解界面的代码几乎肯定不应该知道或关心生物再生多少的细节 - 例如,他们可以用魔法而不仅仅是生命点来重生,或者再生水平取决于他们国家的其他一些功能。来电者不应该在意。

答案 1 :(得分:2)

我会将它添加到abstract BaseCreature中,而不用担心它太多。您的BaseCreature最终可能会有许多有效“关闭”的属性,但另一种方法是创建一个复杂的继承树。由于Java不支持多重继承,因此这会使您抽象出您可能想要的所有组合的能力受挫。

答案 2 :(得分: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开始,因此您必须覆盖想要实际重新生成的子类中的值

编辑删除“implements Regeneative”

答案 3 :(得分:1)

我认为您的设计可能没问题,因为您只需要在实现Regenerative接口的类中包含regenerateValue。因此不需要包含regenerateValue。

否则,您可以查看更复杂的设计模式,这些模式有利于组合而不是继承。通过这种方式,你可以满足在游戏过程中动态地将再生能力与其他“能力”一起添加到怪物的可能性,而不是每次你需要改变你的怪物的行为时重新编译游戏。

答案 4 :(得分: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的子类中,你只需在instanciation期间添加这类怪物的属性集。

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

我在某些情况下使用Id,其中每个tick都没有使用该属性(即更新中没有任何内容),但是例如损坏减少(id =“LightningReduction”),或者修改现有属性列表(删除所有regeneProperty并添加相同值的PoisonProperty的属性...)。

答案 5 :(得分:0)

您可以在界面中添加一个方法,例如getRegnerationValue(),确保具有该界面的所有生物都拥有包含您想要使用的值的方法或值。

答案 6 :(得分:0)

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

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

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

然后,你的基类可以有一些方法,如:

OnStartOfTurn();

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