Общий factory с неизвестными классами реализации

Предположим, что два интерфейса:

public interface FruitHandler<T extends Fruit>
{
    setFruit(T fruit);
    T getFruit();
}

public interface Fruit
{
}

Теперь я хочу, чтобы factory создавал FruitHandlers (например, AppleHander, OrangeHandler,...), но FruitHandlerFactory не знает о необходимых классах обоих интерфейсов (например, в java параметризованный общий статический factory). FruitHandlerFactory должен работать таким образом (где OrangeHandler реализует FruitHandler и Orange реализует Fruit):

FruitHandlerFactory fhf = new FruitHandlerFactory<OrangeHandler,Orange>();
OrangeHandler fh = fhf.create();
Orange orange = (Orange)fh.getFruit();

Это должен быть factory:

public class FruitHandlerFactory<A extends FruitHandler, B extends Fruit>
{
    public FruitHandler create()
    {
        FruitHandler<Fruit> fh = new A<B>();   //<--- ERROR
        fh.setFruit(new B());
        return fh;
    }
}

Где я получаю эту ошибку:

The type A is not generic; it cannot be parameterized with arguments <B>

BTW: Можно ли сделать метод create() статическим?

Ответ 1

Так как generics в Java реализованы с использованием стирания, информация о типе FruitHandlerFactory будет недоступна во время выполнения, что означает, что вы не можете создать экземпляр A (или B) таким образом.

Вы можете, однако, передать объект Class правильного типа, чтобы обойти это:

public class FruitHandlerFactory<H extends FruitHandler<F>, F extends Fruit> {
    final Class<H> handlerClass;
    final Class<F> fruitClass;

    public FruitHandlerFactory(final Class<H> handlerClass, final Class<F> fruitClass) {
        this.handlerClass = handlerClass;
        this.fruitClass = fruitClass;
    }

    public H create() throws InstantiationException, IllegalAccessException {
        H handler = handlerClass.newInstance();
        handler.setFruit(fruitClass.newInstance());
        return handler;
    }
}

Недостатком является то, что вам нужно будет писать имена типов три раза (1), если вы хотите создать экземпляр FruitHandlerFactory:

FruitHandlerFactory fhf = new FruitHandlerFactory<OrangeHandler,Orange>(OrangeHandler.class, Orange.class);

Вы можете несколько уменьшить это, создав метод static createFactory() на вашем FruitHandlerFactory:

static <H extends FruitHandler<F>, F extends Fruit> FruitHandlerFactory<H, F> createFactory(
        final Class<H> handlerClass, final Class<F> fruitClass) {
    return new FruitHandlerFactory<H, F>(handlerClass, fruitClass);
}

и используйте его следующим образом:

FruitHandlerFactory fhf = FruitHandlerFactory.createFactory(OrangeHandler.class, Orange.class);

Ответ 2

Из этот вопрос:

Возможно, попробуйте это?

public class FruitHandlerFactory<A extends FruitHandler<B>, B extends Fruit>