I have a PlayerCharacter class. PlayerCharacter can be extended (e.g. VampirePlayerCharacter vs WerewolfPlayerCharacter)
I have a Trait class. A trait can be expanded (for example, generation or gnosis).
PlayerCharacter has a #withTrait(Trait) method that adds Trait to the collection. PlayerCharacter has a #applyAllTraits() method that goes through the collection and applies each of them to a character.
A VampirePlayerCharacter should be provided with any Trait that can apply to PlayerCharacter , as well as any Trait that can only apply to VampirePlayerCharacter .
So, I added a generic type by creating Trait<PC extends PlayerCharacter>
So there could be BasicTrait<PlayerCharacter> and Generation<VampirePlayerCharacter>
My puzzle:
If the CharacterCharacter character set has Collection<Trait<PlayerCharacter>> , then VampirePlayerCharacter cannot add Trait<VampirePlayerCharacter> to the collection.
If PlayerCharacter collection of attributes Collection<Trait<? extends PlayerCharacter>> Collection<Trait<? extends PlayerCharacter>> , then VampirePlayerCharacter can add Trait<VampirePlayerCharacter> to the collection. However, PlayerCharacter can no longer PlayerCharacter over traits because their type is undefined (it can be Trait<PlayerCharacter> or Trait<VampirePlayerCharacter> or Trait<WerewolfPlayerCharacter> or ...)
If PlayerCharacter collection of attributes Collection<Trait<? super PlayerCharacter>> Collection<Trait<? super PlayerCharacter>> , then VampirePlayerCharacter cannot add Trait<VampirePlayerCharacter> , because VampirePlayerCharacter not a supertype of PlayerCharacter
I'm talking about the breadth of hair from the fact that more specialized features just have to use the cast in the method of applying them, and if you set them incorrectly, they will explode, but I'm sure this is not a new problem, and I just canβt wrap my head around the solution .
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); } }
source share