1

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?

2
  • 1
    You should only ask one question per question. More so considering that your two questions are quite different. Please, remove your second one. You can just make another question with that. It will help you get more and better answers. Commented Aug 16, 2015 at 21:27
  • A very simple way to store object graphs in a relational database is to to have your classes implement Serializable and then store the entire serialized object graph in a database column. You can do something similar by "stringifying" your object into a JSON String and then saving the String to a database field. Both the serialized form and a JSON String can be deserialized into the original object. Care must be exercised so that your serialized forms are efficient and correct. Commented Aug 16, 2015 at 23:29

2 Answers 2

1

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));
Sign up to request clarification or add additional context in comments.

Comments

1

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(){}

    // ...
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.