我处于游戏开发的早期阶段。这是一种像战锤或魔兽一样的回合制游戏。有些生物可以重生他们遭受的伤害并代表我有这样的界面
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?)。我认为它给了一个类不必要的属性,因此是一个糟糕的设计。您认为这种情况的最佳方法是什么?
答案 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中执行其他操作或调用其他方法。