phpnuker
phpnuker

Reputation: 41

Factory objects creator with generics

I want to do a factory pattern in java with generics. My code is:

The interface:

public abstract class Factory<T> {
    public abstract T create();
}

FactoryA class:

public class FactoryA extends Factory<FactoryA> {

    public FactoryA() {

    }

    public FactoryA create() {
        return new FactoryA();
    }

}

FactoryB class:

public class FactoryB extends Factory<FactoryB> {

    public FactoryB() {

    }

    public FactoryB create() {
        return new FactoryB();
    }

}

The main class:

public class FactoryCreator {

    public static <T> T createFactory() {
        Factory<T> t = ?; // is that right way?
        return t.create();
    }

    public static void main(String[] args) {
        FactoryA factoryA = FactoryCreator.createFactory();
        FactoryB factoryB = FactoryCreator.createFactory();
    }
}

The question, what Factory t = need to be equal, or is there any other way?

Upvotes: 0

Views: 1085

Answers (2)

koljaTM
koljaTM

Reputation: 10262

Something like this might work:

public static <T extends Factory> T createFactory(Class<T> clazz) {
    try {
        t = clazz.newInstance();
        return t.create();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return null;
    }
}
...
FactoryA factoryA = FactoryCreator.createFactory(FactoryA.class);

alternatively, without parameters. But then you need two methods.

public static FactoryA createFactoryA() {
   return new FactoryA().create();
}
...
FactoryA factoryA = FactoryCreator.createFactoryA();

Since the Generic types are erased at runtime you have to supply the Class parameter so that the runtime knows what class you are talking about.

Upvotes: 0

ultddave
ultddave

Reputation: 198

Not really sure what you're trying to achieve, but this might help;

public interface Factory<T> 
{
    public T create(String type);
    public T create(String type, Object arg);
    public T create(String type, Object[] args);
}

And then have a class implement that factory interface, like this;

public class TemplateFactory<T> implements Factory {

    @Override
    public T create(String type) throws IllegalArgumentException
    {
        return create(type, null);
    }

    @Override
    public T create(String type, Object arg) throws IllegalArgumentException
    {
        // Convert to array of 1 element
        Object[] arguments = new Object[1];
        arguments[0] = arg;
        return create(type, arguments);
    }

    @Override
    public T create(String type, Object[] args) throws IllegalArgumentException
    {
        // Create array for all the parameters
        Class<?> params[] = (args != null) ? new Class<?>[args.length] : new Class<?>[0];
        if(args != null)
        {
            // Adding the types of the arguments
            for(int i = 0; i < args.length; ++i)
                params[i] = (args[i] != null) ? args[i].getClass() : null;
        }

        try
        {
            // Create a class variable
            Class classLoader = Class.forName(type);
            // Find the right constructor
            Constructor co;
            if(params.length > 0)
                co = classLoader.getConstructor(params);
            else
                co = classLoader.getConstructor();
            // Instantiate the class with the given arguments
            T newObject = (T)co.newInstance(args);
            return newObject;
        }
        catch(Exception e)
        {
            throw new IllegalArgumentException(e.toString());
        }
    }
}

And then use it like this (using some imaginary strategy-classes as an example):

TemplateFactory<StrategyInterface> factory;
factory = new TemplateFactory<>();

factory.create("packageName.StrategyA");
factory.create("packageName.StrategyB");
factory.create("packageName.StrategyC");

The strategy classes (A, B and C) would implement the StrategyInterface-class in this example.

Upvotes: 1

Related Questions