I'm using a Builder pattern to create Item objects in my game, and I want to be able to use item prefixes and suffixes to generate random Items, as in Item.builder().random().build()
. Prefix and Suffix are both enums with ragged fields. All of them have a name
, but some have damage
and luck
fields, for example. How do I access the enums' fields from within the builder?
I have public methods in each enum that return a random Prefix and Suffix, my Item Builder's randomize method calls these and stores the affixes locally. But I can't seem to get at their member variables via reflection. prefix.getClass().getDeclaredField("name").toString
returns java.lang.String roan.ItemPrefix$2.name
instead of it's actual name. Plus it seems hacky to me.
Enum:
enum Prefix {
ARROGANT {
String name = "Arrogant ";
int damage = 20;
int luck = 2;
},
BLOODY {
String name = "Bloody ";
int damage = 30;
},
CURIOUS {
String name = "Curious ";
int luck = 4;
},
private static final int size = Prefix.values().length;
public static Prefix randomPrefix() {
return Prefix.values()[Dice.roll(Prefix.size)];
}
}
Builder:
public static abstract class Builder<T extends Builder<T>> {
// Default values
private String name = "itemName";
private int damage = 5;
private int luck = 0;
protected abstract T self();
public T name(String name) {
this.name = name;
return self();
}
// More builder methods
...
// PROBLEMATIC CODE
public T random() {
Prefix prefix = Prefix.randomPrefix();
this.name = prefix.getClass().getDeclaredField("name").toString();
return self();
}
public Item build() {
return new Item(this);
}
}
}
// Builder helper classes
...
Ideally it would assemble a fully-formed items using the member fields of the enums passed to it. I'm using enum Prefix
rather than an array of Prefix objects because I want to use certain EnumSets elsewhere for subclasses of Item
like Armor
, which can only use certain prefixes.
Your current design depends on 3 anonymous subclasses of the enum Prefix. This is not necessary. Rather try this:
enum Prefix {
ARROGANT ("Arrogant ",20,2), BLOODY("Bloody ",30,0), CURIOUS("Curious ",5, 4);
public String name = "itemName";
public int damage = 5;
public int luck = 0;
Prefix(String name, int damage, int luck) {
this.name = name;
this.damage = damage;
this.luck = luck;
}
...
}
Consequently you will not need reflection to access your fields.
If you really want the alternatives arrogant
, bloody
, curious
to have different schemas, the decision for an enum is wrong. Rather select random in a list of factories, each returning the completely correct configured item for this random selection.