Универсальная фабрика с неизвестными классами реализации

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

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

public interface Fruit
{
}

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

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

Это должна быть фабрика:

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>

Кстати: возможно ли сделать create() метод статический?

2 ответа

Решение

Поскольку дженерики в 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);

Вы можете несколько уменьшить это, производя staticcreateFactory() метод на вашем 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);

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

Возможно попробовать это?

public class FruitHandlerFactory<A extends FruitHandler<B>, B extends Fruit>
Другие вопросы по тегам