Java通用字段

时间:2014-12-03 21:57:56

标签: java generics

我有一个PlayerCharacter类。 PlayerCharacter可以扩展(例如,VampirePlayerCharacter vs WerewolfPlayerCharacter)

我有一个特质课程。特质可以扩展(例如,代或Gnosis)。

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

VampirePlayerCharacter应该能够提供适用于Trait的任何PlayerCharacter,以及只适用于{{1}的任何Trait }}

所以我添加了一个通用类型,使VampirePlayerCharacter

因此,可以有Trait<PC extends PlayerCharacter>BasicTrait<PlayerCharacter>

我的难题:

  • 如果PlayerCharacter的特征集合为Generation<VampirePlayerCharacter>,则Collection<Trait<PlayerCharacter>>无法将VampirePlayerCharacter添加到集合中。

  • 如果Trait<VampirePlayerCharacter>的特征集合为PlayerCharacter,则Collection<Trait<? extends PlayerCharacter>>可以向集合中添加VampirePlayerCharacter。但是,Trait<VampirePlayerCharacter>无法再遍历这些特征,因为它们的类型不确定(可能是PlayerCharacterTrait<PlayerCharacter>Trait<VampirePlayerCharacter>或......)

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

我觉得更专业的特质只需要在他们的应用方法中使用强制转换,如果你不恰当地设置它们,它们会爆炸 - 但我是某些

PlayerCharacter

1 个答案:

答案 0 :(得分:2)

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

基本上你必须做类似的事情:

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构建对象,则可能会考虑使用构建器或工厂,因此您不需要使用泛型。