Reputation: 107
SQLite and Java Beginner here,
I'm currently working on a game where the player obtains random items, since I plan on including a huge amount of items, I have stored the item information in a SQLite db.
The thing is, my item objects have their own behavior objects in addition to fields like String name, int power, etc. This makes converting results to objects a more complicated endeavor. Currently I am referring to these behaviors as Strings in the db, and then instantiating the correct behavior object using a Switch statement at Item Creation. This is just a semi-fictional example to show what I mean:
Item item = new Item();
String name = resultSet.getString("Name");
String activationEffect = resultSet.getString("Activation Effect");
item.setName(name);
switch (activationEffect){
case "Smack Fools":
item.setActivationEffect(new SmackFools());
break;
case "Have a Nap":
item.setActivationEffect(new NapTime());
break;
default:
break;
Alternatively I could make item.setActivationEffect take a String and do the switch statement itself, but that doesn't really change anything. Is there a better way to accomplish this?
Upvotes: 1
Views: 273
Reputation: 8823
The factory pattern will be useful for you:
Assuming that your classes SmackFools
and NapTime
have a common superclass named, for example, ActivationEffect
, you have to code one factory class like this:
class EffectFactory
{
private final Map<String, Class> map=createMap();
private Map<String, Class> createMap()
{
Map<String, Class> map=new HashMap<String, Class> ();
// ... Store here the allowed mappings:
// map.put("Smack fools", my.package.SmackFools.class);
// map.put("Have a nap", my.package.NapTime.class);
return map;
}
public ActivationEffect createActivationEffect(String name){
// ... Get a Class indexing the map by name, and instantiate it.
// If not found, throw an exception (for example, IllegalArgumentException).
}
}
In this way, if you want to add a new implementation of ActivationEffect
, you'll just have to add one line in createMap
. And if you want it more flexible, you can store the mappings in a .properties file and modify createMap
to read that file.
Another additional useful pattern in this case would be implementing the factory as a singleton:
final class EffectFactory
{
private static final EffectFactory INSTANCE=new EffectFactory();
public static EffectFactory getInstance()
{
return INSTANCE;
}
private EffectFactory(){}
// ...
}
Upvotes: 1
Reputation: 3200
You need a way to relate each behaviour name (a String
) with its class (to create a new object of that class). Since the behaviour names are not exactly equal to the classes name you can't directly use reflection for that.
So there is no way around it, you have to make a table.
There are many ways to do such table, yours with switches is a valid one. Though probably you don't like its verbosity; you need three lines for each new behaviour.
In the following code all of this is isolated in a class.
You need only to add a single line each time you add a new behaviour.
I am assuming that all behaviours extend a common ActivationEffect
class, or that all implement a common ActivationEffect
interface.
class ActivationEffectsFactory {
private static Map<String, Class<? extends ActivationEffect>> map = new HashMap<>();
static
{
add( "Smack Fools", SmackFools.class );
add( "Have a Nap", Naptime.class );
}
private static void add(String name, Class<? extends ActivationEffect> behaviour) {
assert !map.containsKey(name);
assert behaviour!=null && name!=null;
map.put(name, behaviour);
}
public static ActivationEffect build(String name)
{
ActivationEffect res;
try {
res = map.get(name).newInstance();
} catch (InstantiationException | IllegalAccessException ex) {
res = null;
}
if ( res==null )
throw new IllegalArgumentException( "Incorrect behaviour name : " + name );
return res;
}
}
When you want to add a new effect you just need to do so in the static block.
To get a new object of the proper class from its name you would :
item.setActivationEffect(ActivationEffectsFactory.build(activationEffect));
Upvotes: 1