Универсальная фабрика с неизвестными классами реализации
Давайте предположим два интерфейса:
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);
Вы можете несколько уменьшить это, производя 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);
Из этого вопроса:
Возможно попробовать это?
public class FruitHandlerFactory<A extends FruitHandler<B>, B extends Fruit>