This will be a bit hard to explain, but I will try my best.
I want to have multiple items that, when clicked, each have a different result. For the rest, they all have the same variables. So basically, I have a class Item, and subclasses Ball, Rope, Book, and many, many more to come. I want to be able to easily add items if I want to. The Item class has a String name, String description and a method 'onUse' that each of the subclasses override.
I would like to handle this as dynamical as possible, meaning I would like a single method in my Frame/Activity (This is for Android but Java applies) to execute the method.
I'm using this for a single method:
public void useItem(Item i)
{
i.onUse();
}
My problem is that I have the different items saved in a database. I want to randomly grab one of the items from the database and instance it; except I have no way of knowing which subclass to instance it as. I tried saving the datatype in the database but that's not really working out... Pseudocode:
//Database cursor stuff
//...
String itemType = c.getString(6);
//Get the class name if possible
Class itemClass= null;
try {
itemClass = Class.forName(itemType);
} catch (ClassNotFoundException)
e.printStackTrace();
}
Item l = null;
// Check here what type it is!
if (itemClass.equals(Ball.class)) {
l = new Ball(name,description);
} else if(lootClass.equals(Book.class)){
l = new Book(name,description);
}
Seeing as there are so many different items this isn't really great as I would have to iterate through loads of classes (plus I often the get ClassNotFoundException)
What say you, StackOverflow? What would be the best approach?
The factory pattern is probably the way to go. If you store the fully qualified name in the DB then you can create a factory that reads the value and instantiates a new Item using the following:
Item item = (Item) Class.forName(theDBField).newInstance();
item.setName(name);
item.setDescription(desc);
Which means a much more concise factory that doesn't have to know about all the classes it can build. I really dislike having to update a factory everytime I add a new implementation and this is a simple way to avoid it.
to do this you will have to add getters and setters to the item interface.
In your case I would use a Factory method pattern (aka Factory pattern).
Factory method pattern is a creational pattern. The creational patterns abstract the
object instantiation process by hiding how the objects are created and make the system independent of the object creation process.
Lets try to implement how it should work:
Model
public abstract class Model {
protected abstract void init();
}
Book
public class Book extends Model {
@Override
protected void init() {
System.out.println("I'm a Book");
}
}
Ball
public class Ball extends Model {
@Override
protected void init() {
System.out.println("I'm a Ball");
}
}
DbModelFactory
public abstract class DbModelFactory {
public abstract Model getModel(int modelId);
}
SimpleDbModelFactory
public class SimpleDbModelFactory extends DbModelFactory {
@Override
public Model getModel(int modelId) {
Model model = null;
if(modelId == Const.MODEL_BOOK) {
model = new Book();
}
else if(modelId == Const.MODEL_BALL) {
model = new Ball();
}
else {// throw Exception
}
return model;
}
}
Const
public class Const {
public static final int MODEL_BOOK = 0;
public static final int MODEL_BALL = 1;
}
Launcher
public class Launcher {
public static void main(String[] args) {
DbModelFactory factory = new SimpleDbModelFactory();
Model book = factory.getModel(0);
book.init(); // I'm a Book
Model ball = factory.getModel(1);
ball.init(); //I'm a Ball
}
}
Factory pattern returns one of the several product subclasses. You should use a factory
pattern If you have a super class and a number of subclasses and based on some data provided, you have to return the object of one of the subclasses
Now we have 2 Models
book
and ball
and we don't care that both are actually Model
.