Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

use variable with "new" when creating object

Tags:

java

I am designing a virtual aquarium. I have a class: Fish which I inherit to create classes of different species. The user can select the species in a combo box and click a button to put the fish in the tank. I use the following code to create the fish:

    switch(s){
        case "Keegan" :
            stock.add(new Keegan(this, x,y));
            break;
        case "GoldenBarb" :
            stock.add(new GoldenBarb(this, x,y));

"stock" is a LinkedList and "s" is the String selected in the Jcombobox. As it stands I will have to create a long switch when I add a bunch of different species. I would like the code to look like:

stock.add(new s(this,x,y));

and dispense with the switch such that all I have to do is create the class and add its name to the combo box and have it work. Is there a way to do so? Any help is appreciated.

like image 784
laertiades Avatar asked Dec 17 '12 03:12

laertiades


People also ask

How do you make an object using the new operator?

Class objects can be created in Java by using the new operator. A class is instantiated by the new operator by allocating memory for the object dynamically and then returning a reference for that memory. A variable is used to store the memory reference.

Which variables are created when an object is created with new keyword?

Instance variables are created when an object is created with the use of the keyword 'new' and destroyed when the object is destroyed. Static variables are created when the program starts and destroyed when the program stops. Instance variables can be accessed directly by calling the variable name inside the class.

Can we create an object of a variable?

If you use an object variable without declaring it first, the data type of the object variable is Variant by default. You can declare an object variable with the Object data type when the specific object type is not known until the procedure runs. Use the Object data type to create a generic reference to any object.

How do you create an object variable?

You declare a variable of the Object Data Type by specifying As Object in a Dim Statement. You assign an object to such a variable by placing the object after the equal sign ( = ) in an assignment statement or initialization clause.


2 Answers

You want to use a bunch of factory objects, stored in a Map under the string keys that you use in the switch.

These are the classes for the various fish you should already have.

abstract class FishBase {}

class Keegan extends FishBase {
    Keegan(Object _this, int x, int y) {
        // ...
    }
}
class GoldenBarb extends FishBase {
    GoldenBarb(Object _this, int x, int y) {
        // ...
    }
}

An interface for all the fish factories. A fish factory represents a way to create some type of fish. You didn't mention what the constructor signature is so I just picked some types.

interface IFishFactory {
    FishBase newFish(Object _this, int x, int y);
}

Set up one factory for every fish type. These obviously don't need to be anonymous classes, I'm using them to cut down on clutter.

Map<String, IFishFactory> fishFactories = new HashMap<>();

fishFactories.put("Keegan", new IFishFactory() {
    public FishBase newFish(Object _this, int x, int y) {
        return new Keegan(_this, x, y);
    }
});

fishFactories.put("GoldenBarb", new IFishFactory() {
    public FishBase newFish(Object _this, int x, int y) {
        return new GoldenBarb(_this, x, y);
    }
});

Then just pick the factory from the Map using the string you already have. You might want to check whether a factory for the given name exists.

stock.add(fishFactories.get(s).newFish(this, x, y));

Now, if all your fish classes have the exact same constructor signature, you can create a single factory class that can handle all of them using reflection, and get rid of some boilerplate.

class ReflectionFishFactory implements IFishFactory {
    Constructor<? extends FishBase> fishCtor;
    public ReflectionFishFactory(Class<? extends FishBase> fishClass) 
            throws NoSuchMethodException {

        // Find the constructor with the parameters (Object, int, int)
        fishCtor = fishClass.getConstructor(Object.class, 
                                            Integer.TYPE, 
                                            Integer.TYPE);
    }


    @Override
    public FishBase newFish(Object _this, int x, int y) {
        try {
            return fishCtor.newInstance(_this, x, y);
        } catch (InstantiationException
                | InvocationTargetException
                | IllegalAccessException e) {
            // this is terrible error handling
            throw new RuntimeException(e);
        }
    }
}

Then register it for every applicable subclass.

for (Class<? extends FishBase> fishClass : 
        Arrays.asList(Keegan.class,GoldenBarb.class)) {
    fishFactories.put(fishClass.getSimpleName(), 
                      new ReflectionFishFactory(fishClass));
}
like image 197
millimoose Avatar answered Sep 27 '22 16:09

millimoose


I think reflection might be what you are looking for. This allows you to avoid the switch statement, which is what you are asking.

Reflection (among other things) allows you to run methods with just strings. So in Java, where you would normally call a method like this:

new Foo().hello();

With Reflection, you can use a string to call the method, like this:

Class<?> clazz = Class.forName("Foo");
clazz.getMethod("hello").invoke(clazz.newInstance());

Java Constructor Reflection example.


Regarding the Factory pattern (referring now to other answers), as I understand it, that is just encapsulating the switch statement (or whatever method you choose to use). The Factory pattern itself is not a means of avoiding the switch statement. The Factory Pattern is a good thing, but not what you were asking. (You will probably want to use the factory pattern in any case).

like image 37
lindon fox Avatar answered Sep 27 '22 17:09

lindon fox