Java 泛型字段



我有一个PlayerCharacter类。玩家角色可以扩展(例如,吸血鬼玩家角色 vs 狼人玩家角色(

我有一个特质类。 特征可以扩展(例如,世代或灵知(。

PlayerCharacter有一个方法,#withTrait(Trait) ,它将特征添加到集合中。 PlayerCharacter有一个方法,#applyAllTraits()该方法循环遍历集合并将每个集合应用于角色。

一个VampirePlayerCharacter应该能够被赋予任何可以适用于PlayerCharacterTrait,以及任何只能适用于VampirePlayerCharacterTrait

所以我添加了一个泛型类型,使Trait<PC extends PlayerCharacter>

因此,可以有BasicTrait<PlayerCharacter>Generation<VampirePlayerCharacter>

我的难题:

  • 如果 PlayerCharacter 的特征集合Collection<Trait<PlayerCharacter>>,则VampirePlayerCharacter无法向集合添加Trait<VampirePlayerCharacter>

  • 如果PlayerCharacter的特征集合Collection<Trait<? extends PlayerCharacter>>,则VampirePlayerCharacter可以向集合添加一个Trait<VampirePlayerCharacter>。 但是,PlayerCharacter不能再循环这些特征,因为它们的类型是不确定的(可能是Trait<PlayerCharacter>Trait<VampirePlayerCharacter>Trait<WerewolfPlayerCharacter>或......

  • 如果PlayerCharacter的特征集合是Collection<Trait<? super PlayerCharacter>>的,那么VampirePlayerCharacter不能添加Trait<VampirePlayerCharacter>,因为VampirePlayerCharacter不是PlayerCharacter的超类型

我说

更专业的特质只需要在他们的应用方法中使用一个演员,如果你设置得不恰当,它们就会爆炸——但我确信这不是一个新问题,我只是无法围绕解决方案。

class PlayerCharacter {
  private int str;
  List<Trait<?>> traits = new ArrayList<>();
  PlayerCharacter withStrength(int str) {
    this.str = str;
    return this;
  }
  PlayerCharacter withTrait(Trait trait) {
    this.traits.add(trait);
    return this;
  }
  void applyTraits() {
    traits.forEach((Trait<?> t) -> t.apply(this));
  }
}
class VampirePlayerCharacter extends PlayerCharacter {
  private int fangLength;
  VampirePlayerCharacter  withFangLength(int fangLength) {
    this.fangLength = fangLength;
    return this;
  }
}
abstract class Trait<PC extends PlayerChracter> {
  void apply(PC pc);
}
class StrengthTrait extends Trait<PlayerCharacter> {
  private int str;
  StrengthTrait(int str) {
    this.str = str;
  }
  void apply(PlayerCharacter pc) {
    pc.withStrength(str);
  }
}
class FangLengthTrait extends Trait<VampirePlayerCharacter> {
  private int fangLength;
  FangLengthTrait(int fangLength) {
    this.fangLength = fangLength;
  }
  void apply(VampirePlayerCharacter pc) {
    pc.withFangLength(fangLength);
  }
}

问题是您需要将继承保留为泛型类型信息。

基本上,您必须执行以下操作:

class PlayerCharacter<P extends PlayerCharacter<P>> {
    List<Trait<? super P>> myTraits;
}
class VampirePlayer extends PlayerCharacter<VampirePlayer> {...}
abstract class Trait<P extends PlayerCharacter<P>> {
    abstract void apply(P player);
}
class FangLengthTrait extends Trait<VampirePlayer> {...}

不过,它开始变得非常笨重。您可以通过从构图接近来改善这种情况:

class Attributes {}
class Base extends Attributes {
    int strength;
}
class Vampire extends Base {
    int fangLength;
}
class Player<A extends Attributes> {
    final A attributes;
    final List<Trait<? super A>> traits = new ArrayList<>();
    Player(A attributes) {
        this.attributes = attributes;
    }
    void applyTraits() {
        for(Trait<? super A> t : traits)
            t.apply(this);
    }
}
interface Trait<A extends Attributes> {
    void apply(Player<? extends A> player);
}
class StrengthTrait implements Trait<Base> {
    @Override
    public void apply(Player<? extends Base> player) {
        player.attributes.strength = 1000;
    }
}
class FangLengthTrait implements Trait<Vampire> {
    @Override
    public void apply(Player<? extends Vampire> player) {
        player.attributes.fangLength = 100;
    }
}
final class Factory {
    private Factory() {}
    public static Player<Base> newPlayer() {
        return new Player<Base>(new Base());
    }
    public static Player<Vampire> newVampire() {
        return new Player<Vampire>(new Vampire());
    }
}

我个人仍然觉得它很笨拙。如果您主要只是使用这些Trait来构造对象,则可以考虑使用构建器或工厂,这样就不需要使用泛型。

最新更新