简体   繁体   English

在哪里放置与接口相关的变量,该变量不是静态的且不是最终的

[英]Where to put a interface related variable that it is not static and final

I am in a very early stage of game development. 我正处于游戏开发的初期。 It is some sort of turn based game like Warhammer or Warcraft. 这是某种基于回合的游戏,例如《战锤》或《魔兽争霸》。 Some creatures can regenerate the damage they have suffered and to represent this I have a interface like this 有些生物可以再生他们遭受的伤害,并代表这个我有一个这样的界面

public interface Regenerative {
    void regenerates();
}

So a creature that regenerates is 所以一个再生的生物是

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

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

The problem I face is that not all the creatures regenerates the same ammount of hit points so I have to place that amount (regenerateValue) somewhere. 我面临的问题是,并非所有生物都能再生相同数量的生命值,因此我必须将其数量(regenerateValue)放置在某个地方。 Since I cannot put it on the interface (because I don't want the ammount to be the same to all the creatures) I have thought in adding a new property to the creature class 由于我无法将其放置在界面上(因为我不希望所有生物的数量都相同),所以我考虑在生物类中添加新属性

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

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

but I don't like it this way (why a creature that doesn't regenerate should have a regenerateValue of 0?). 但是我不喜欢这种方式(为什么不再生的生物的regenerateValue应该为0?)。 I think it is giving a class unnecesary properties and thus a bad design. 我认为它给了类不必要的属性,因此设计很糟糕。 What do you think is the best approach for this case? 您认为此案例的最佳方法是什么?

The problem I face is that not all the creatures regenerates the same ammount of hit points so I have to place that amount (regenerateValue) somewhere. 我面临的问题是,并非所有生物都能再生相同数量的生命值,因此我必须将其数量(regenerateValue)放置在某个地方。

Why does it have to be a field anywhere? 为什么它必须在任何地方都是一个领域 Some implementations of the interface might use a different value per instance; 接口的某些实现可能会对每个实例使用不同的值。 others might use a constant value. 其他人可能使用恒定值。

This is an implementation detail - and thus inappropriate for the interface. 这是实现细节 ,因此不适用于该接口。 You could potentially put it in an abstract superclass which implements the interface, of course. 当然,您可以将其放入实现该接口的抽象超类中。

Code which knows about the interface almost certainly shouldn't know or care the details of how much a creature regenerates - maybe they regenerate in terms of magic rather than just hit points, for example, or maybe the level of regeneration depends on some other function of their state. 知道界面的代码几乎肯定不应该知道或关心生物再生多少的细节-例如,它们是根据魔术而不是仅仅根据生命值再生的,或者再生的水平取决于其他功能他们的状态。 Callers shouldn't care. 来电者不在乎。

I would add it to the abstract BaseCreature and not worry about it too much. 我会将其添加到abstract BaseCreature中,不必太担心它。 Your BaseCreature may end up with lots of properties which are effectively "turned off" but the alternative is to create a complex inheritance tree. 您的BaseCreature最终可能会具有许多有效“关闭”的属性,但替代方法是创建一个复杂的继承树。 As Java doesn't support multiple inheritance this will frustrate your ability to abstract all the combinations you might like away. 由于Java不支持多重继承,因此这会挫败您抽象所有可能想要的组合的能力。

What if all monster regenerate, but some of them with 0 regenerate value (the same as not regenerating)? 如果所有怪物都已重新生成,但其中一些具有0的重新生成值(与未重新生成相同),该怎么办?

So you don't need the inferface: 因此,您不需要下面的代码:

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

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

The regenerateValue starts with 0, so you have to override the value in subclasses that want to actually regenerate regenerateValue以0开头,因此您必须重写要实际重新生成的子类中的值

Edited to remove the " implements Regeneative" 编辑删除了“工具再生”

I think your design is probably ok, as you would only need to include a regenerateValue in the classes that implement the Regenerative interface. 我认为您的设计可能还可以,因为您只需要在实现Regenerative接口的类中包括regenerateValue即可。 So there would be no need to include a regenerateValue. 因此,无需包含regenerateValue。

Otherwise you could look at more complex design patterns that favor composition over inheritance. 否则,您可以查看更偏重于继承而非继承的更复杂的设计模式。 This way you could cater for the possibility of dynamically adding Regenerative abilities to a monster along with other 'abilities' during the game, rather than having to recompile the game each time you need to make change the behaviour of your monster. 这样,您就可以适应在游戏过程中向怪物动态添加再生能力以及其他“能力”的可能性,而不必在每次需要更改怪物行为时都重新编译游戏。

The solution i use may be a bit over-ingeniered, but this allow for a lot of extension (regeneration, poison, protection...) 我使用的解决方案可能有点过头了,但这可以进行很多扩展(再生,毒害,保护...)

I use of interface "CreatureProperties" that define a integer value along with an id, and can perform action on a monster at each turn. 我使用接口“ CreatureProperties”来定义一个整数值和一个id,并且可以在每个回合上对怪物执行操作。 You subclass those properties to perform a given property 您可以将这些属性子类化以执行给定的属性

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);
          }
       } 
    }

in the subclass for SomeMonster, you simply add during instanciation the set of properties for this type of monster. 在SomeMonster的子类中,只需在实例化过程中添加此怪物类型的属性集即可。

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

I'm using the Id in some case where the property is not used each tick (ie nothing in the update), but for example damage reduction (id="LightningReduction"), or to modify the list of existing properties (a property that remove all regenerationProperty and add PoisonProperty of same value...). 在某些情况下,我会使用Id,但该属性不会在每个刻度上都被使用(例如,更新中没有任何内容),而是例如减少伤害(id =“ LightningReduction”)或修改现有属性列表(删除所有再生属性并添加相同值的PoisonProperty ...)。

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

The question you should ask yourself is this: if a creature should regenerate, how do you know that? 您应该问自己的问题是:如果一个生物应该再生,您怎么知道? Will it implement a different (or extending) base class? 它将实现不同的(或扩展的)基类吗? one that implements Regenerative? 一种实现再生的?

If the answer is that you will extend the base class (to something like BaseRegeneratingCreature) and all regenerating creatures will extend that class, then this is your answer: BaseRegeneratingCreature should implement that interface, and have all properties required for regenerating. 如果答案是您将扩展基类(扩展到BaseRegeneratingCreature之类的东西),并且所有正在再生的生物都将扩展该类,那么这就是您的答案:BaseRegeneratingCreature应该实现该接口,并具有再生所需的所有属性。

All non-regenerating creatures should directly extend BaseCreature (or another extending class), and will not need the regeneration related properties. 所有非再生生物都应直接扩展BaseCreature(或另一个扩展类),并且不需要再生相关属性。

Then, your base class could have some method like: 然后,您的基类可以具有以下方法:

OnStartOfTurn();

which will, in BaseRegeneratingCreature, call regenerates() (and then probably call super()), and in BaseCreature do something else or call other methods. 它会在BaseRegeneratingCreature中调用regenerates()(然后可能调用super()),然后在BaseCreature中执行其他操作或调用其他方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM