我有一个PlayerCharacter类。玩家角色可以扩展(例如,吸血鬼玩家角色 vs 狼人玩家角色(
我有一个特质类。 特征可以扩展(例如,世代或灵知(。
PlayerCharacter
有一个方法,#withTrait(Trait)
,它将特征添加到集合中。 PlayerCharacter
有一个方法,#applyAllTraits()
该方法循环遍历集合并将每个集合应用于角色。
一个VampirePlayerCharacter
应该能够被赋予任何可以适用于PlayerCharacter
的Trait
,以及任何只能适用于VampirePlayerCharacter
的Trait
。
所以我添加了一个泛型类型,使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
来构造对象,则可以考虑使用构建器或工厂,这样就不需要使用泛型。