conorgriffin
conorgriffin

Reputation: 4339

Instantiating subclasses in java

I have an abstract class like so:

public abstract class MyAbstractClass {

    protected String greeting;

    public void run() {
        doSomething();
    }

    public abstract void doSomething();
}

... and a subclass like so:

public class MyClass extends MyAbstractClass {

    public MyClass() {
        this.greeting = "Hello, World!";
    }

    public void doSomething() {
        System.out.println(greeting);
    }

    public static void main(String[] args) {
        MyAbstractClass c = new MyClass();
        c.run();
    }
}

I'm going to be creating multiple subclasses, all of them will have the same main method that just instantiates the subclass. Is there a cleaner way of writing this so I don't need to duplicate the main method in every subclass with a different subclass name? So if I create a new subclass called MyOtherClass I don't need to put a main method in with MyAbstractClass c = new MyOtherClass();

I guess I can do it the other way round, where I run the main from the abstract class and instantiate the subclass in there, but then each time I want to change which subclass is instantiated I'd obviously need to change the class name after new. I suppose what I'm looking for is a way to define the main method in the abstract class in such a way that when I run the subclass, it instantiates a copy of the subclass and not the abstract class. If that makes sense...

Upvotes: 0

Views: 10134

Answers (2)

Óscar López
Óscar López

Reputation: 236004

This seems like a good fit for the factory method pattern. Try something like this:

public abstract class MyAbstractClass {

    protected String greeting;

    public void run() {
        doSomething();
    }

    public abstract void doSomething();

    public abstract MyAbstractClass makeClass();

}

public class MyClass1 extends MyAbstractClass {

    public MyClass1() {
        this.greeting = "Hello, World!";
    }

    @Override
    public void doSomething() {
        System.out.println(greeting);
    }

    @Override
    public MyAbstractClass makeClass() {
        return new MyClass1();
    }

}

Then, whenever you need to create a specific instance just call makeClass() in a single implementation of the main() method located in the place you consider most convenient, for instance in MyAbstractClass:

MyAbstractClass mac = new MyClass1();
MyAbstractClass obj = mac.makeClass();

The last line will return an appropriate instance depending on the class used for instantiating the concrete object.

Upvotes: 2

JB Nizet
JB Nizet

Reputation: 691765

This is where dynamic class loading can be useful. If all your subclasses agree to have a no-arg constructor, you can simply use a single Main class with the main method, and pass the class to use as argument:

java com.foo.bar.Main com.foo.bar.MyFrouteenthSubclass

The main method would simply look like this:

public static void main(String[] args) throws Exception {
    String className = args[0];
    MyAbstractClass object = (MyAbstractClass) Class.forName(className).newInstance();
    object.run();
}

You could also assign a name to all your subclasses and store on instance of each of them in a Map<String, MyAbstractClass>, and simply call the main class with the name of the class as argument:

java com.foo.bar.Main fourteen

Upvotes: 2

Related Questions