views:

77

answers:

3

I'm working on robot simulation in Java (a Swing application). I have an abstract class "Robot" from which different types of Robots are derived, e.g.

public class StupidRobot extends Robot {
   int m_stupidness;
   int m_insanityLevel;
   ...
}

public class AngryRobot extends Robot {
   float m_aggression;
   ...
}

As you can see, each Robot subclass has a different set of parameters.

What I would like to do is control the simulation setup in the initial UI. Choose the number and type of Robots, give it a name, fill in the parameters etc.

This is one of those times where being such a dinosaur programmer, and new to Java, I wonder if there is some higher level stuff/thinking that could help me here. So here is what I've got:

(1) User Interface

Scrolling list of Robot types on the left. "Add >>" and "<< Remove" buttons in the middle. Default-named scrolling list of Robots on the right. "Set Parameters" button underneath. (So if you wanted an AngryRobot, you'd select AngryRobot on the left list, click "Add>>" and "AngryRobot1" would show up on the right.)

When selecting a Robot on the right, click "Set Parameters..." button which would call yet another model dialog where you'd fill in the parameters. Different dialog called for each Robot type.

(2) Data structures an implementation

As an end-product I think a HashMap would be most convenient. The keys would be Robot types and the accompanying object would be all of the parameters. The initializer could just retrieve each item one and a time and instantiate. Here's what the data structures would look like:

enum ROBOT_TYPE {STUPID, ANGRY, etc}

public class RobotInitializer {
    public ROBOT_TYPE m_type;
    public string m_name;
    public int[] m_int_params;
    public float[] m_float_params;
    etc.

The initializer's constructor would create the appropriate length parameter arrays based on the type:

public RobotInitializer(ROBOT_TYPE type, int[] int_array, float[] float_array, etc){
     switch (type){
        case STUPID:
            m_int_params = new int[STUPID_INT_PARAM_LENGTH];
            System.arraycopy(int_array,0,m_int_params,0,STUPID_INT_PARAM_LENGTH);

        etc.

Once all the RobotInitializers are instantiated, they are added to the HashMap.

Iterating through the HashMap, the simulation initializer takes items from the Hashmap and instantiates the appropriate Robots.

Is this reasonable? If not, how can it be improved?

Thanks

+3  A: 

You can use reflection to load types dynamically at runtime. See Class.forName to see how you can get a Class given it's fully qualified name. Then you can use isAssignableFrom method to check that the class is a subclass of Robot. You can define some template methods in Robot to let the subclasses specify concrete behavior (e.g. which properties should be initialized). Once you've got the class definition, you can use the newInstance() method to create instances of Robot (the class must have a default constructor, or else you should use the getConstructors() method and use the one you want).

I know there is another way of loading class definitions given the full path of the class file, but can't remember how right now.

Fede
+1  A: 

You can also use an RMIClassLoader, although i would recommend Fede's response if you can use it that way.

aperkins
+1  A: 

As noted, you could make a Robot an implementation of a RobotInterface. Then:

Class aRobotClass = Class.forName("robotClassName"); //or similar
Class[] aRobotClassImplements = aRobotClass.getIterfaces();
// Then ensure that "RobotInterface" exists in the aRobotClassImplements array.

The RobotInterface should define getters and setters for the Robot properties.

I assume eash robot can have a range of different properties. It's possible to dynamically examine the Robot instance and create appropriate buttons/controllers. For instance:

Field[] robotFields = aRobotClass.getFields();

for (Field field : robotFields) {
   JButton jbutton = new JButton(field.getName());
   //assuming this class implements ActionListener
   jbutton.addActionListener(this);
   // Then assume we have a private class representing a button )
   this.hashMapOrVectorOfButtons.add(new PrivateButton(field));
   jpanel.add(jbutton);
   // etc etc
}

Later in actionPerformed, loop over the hashmap or vector of registered buttons. (field.getName().equals(actionEvent.getActionCommand())). Then manipulate the appropriate field in your Robot instance.

matiasf