5

I'm having an interface "Parent", and multiple classes (say Abc.java, Def.java, and Xyz.java) implementing the interface. Now I want to do something like this:

Parent factoryMethod(String condition){
    Parent p = null;
    if(condition.equals("Abc"))
        p = new Abc();
    else if(condition.equals("Def"))
        p = new Def();
    else if(condition.equals("Xyz"))
        p = new Xyz();
    return p;
}

Basically I'm passing the name of the class to be instantiated as the parameter to the method. What is the best way to be doing this? Should I use reflection for this? Its not just 3 classes, there might be a lot more. So I don't want to write if/else.

Thanks.

M A
  • 71,713
  • 13
  • 134
  • 174
drunkenfist
  • 2,958
  • 12
  • 39
  • 73
  • 1
    Are you guaranteed that **all** implementing classes have a default (no parameter) constructor (either implicit or explicit)? – PM 77-1 Feb 13 '15 at 21:53
  • If yes to @PM77-1's comment, I would suggest reflection as per this post: http://stackoverflow.com/questions/14680954/instantiate-java-classes-which-implements-specific-interface-using-reflection – ThePerson Feb 13 '15 at 21:53
  • You're already doing it the way I would suggest. – Kevin Krumwiede Feb 13 '15 at 21:56
  • If you're going to do it this way, you should do Abc.class.getSimpleName().equals(condition) ideally. – Richard Feb 13 '15 at 22:31

4 Answers4

3

One way is to define the method as a generic one, with a type parameter extending Parent, and then create the instance by reflection:

<T extends Parent> T factoryMethod(Class<T> clazz) throws Exception {
    return (T) clazz.newInstance();
}

You can then use the method as follows:

Abc abc = obj.factoryMethod(Abc.class);
Def def = obj.factoryMethod(Def.class);

// The below won't compile if SomeOtherClass does not implement Parent
SomeOtherClass instance = obj.factoryMethod(SomeOtherClass.class); 

However this assumes that all subclasses of Parent have no-argument constructor (either they define a no-argument constructor or they don't define any constructor, hence having a default constructor available).

M A
  • 71,713
  • 13
  • 134
  • 174
1

You could use an enum to implement a strategy pattern like so:

public enum ParentFactory {
    Abc(Abc.class),
    Def(Def.class),
    Xyz(Xyz.class);

    private Class<? extends Parent> childClass;

    private ParentFactory(Class<? extends Parent> childClass) {
        this.childClass = childClass;
    }

    public <T extends List> T getParentInstance() throws InstantiationException, IllegalAccessException {
        return (T) childClass.newInstance();
    }
}


public static void main(String[] args) throws InstantiationException, IllegalAccessException {
    ParentFactory parentFactory = ParentFactory.valueOf("Abc");
    Parent parent = parentFactory.getParentInstance();
}
SergeyB
  • 9,478
  • 4
  • 33
  • 47
0

You can chose the constructor to be used on the basis of the name of the class you are trying to create an object for. Something like:

Class<?> theClass = Class.forName(condition); Constructor<?> theClassConstructor = theClass.getConstructor(); Object object = theClassConstructor.newInstance(new Object[] { args });

aa333
  • 2,556
  • 16
  • 23
0

If you know the full class name, you could use the Reflection API like this :

try {
    return Class.forName(condition).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
    // do something with exception
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423