使用Java中的通用子类型对象创建通用工厂

时间:2014-03-07 09:42:54

标签: java generics inheritance factory

我在Java中编写了一个converter structure,我想创建一个工厂。

我的基本想法是传入一个有效类型的类并接收一个有效的子类型转换器,但是失败了泛型和继承部分。

这是我的界面:

interface ItemRequestConverterFactory {

  public <IR extends ItemRequest> ItemRequestConverter<IR> newInstance(Class<IR> clazz);

}

和实施:

public class DefaultItemRequestConverterFactory implements ItemRequestConverterFactory {

  @Override
  public <IR extends ItemRequest> ItemRequestConverter<IR> newInstance(Class<IR> clazz) {
    if (clazz.equals(CreatePartRequestConverter.class))
    return new CreatePartRequestConverter();

    return null;
  }

}

不幸的是,Eclipse说:“类型不匹配:无法从CreatePartRequestConverter转换为ItemRequestConverter”。

我的通用签名中的问题在哪里?

1 个答案:

答案 0 :(得分:3)

您似乎在类型参数与它们实际应代表的类型之间存在不匹配:您正在将Class<IR>传递给newInstance方法。这是一个代表ItemRequest的类。但是,您将此类实例与可能是ItemRequestConverter接口的实现的类进行比较。

虽然在向CreatePartRequestConverter类添加适当的类型参数时会编译,但这可能不是您想要实现的:

interface ItemRequestConverter<IR extends ItemRequest>{}
interface ItemRequest{}
interface ItemRequestConverterFactory 
{
    public <IR extends ItemRequest> ItemRequestConverter<IR> newInstance(Class<IR> itemRequestClass);
}
class CreatePartRequestConverter<IR extends ItemRequest> implements ItemRequestConverter<IR>
{
}

class DefaultItemRequestConverterFactory implements ItemRequestConverterFactory 
{

    @Override
    public <IR extends ItemRequest> ItemRequestConverter<IR> newInstance(Class<IR> itemRequestClass) 
    {
        // Does not make sense: Comparing ItemRequest class with something
        // that is probably an implementation of ItemRequestConverter
        if (itemRequestClass.equals(CreatePartRequestConverter.class))
        {
            return new CreatePartRequestConverter<IR>();
        }
        return null;
    }
}

根据您实际想要实现的目标,您可以将ItemRequestConverter类传递给工厂方法(并相应地参数化方法):

interface ItemRequestConverter<IR extends ItemRequest>{}
interface ItemRequest{}
interface ItemRequestConverterFactory 
{
    public <IRC extends ItemRequestConverter<?>> ItemRequestConverter<?> newInstance(Class<IRC> itemRequestConverterClass);
}
class CreatePartRequestConverter implements ItemRequestConverter<ItemRequest>
{
}

class DefaultItemRequestConverterFactory implements ItemRequestConverterFactory 
{
    @Override
    public <IRC extends ItemRequestConverter<?>> ItemRequestConverter<?> newInstance(
        Class<IRC> itemRequestConverterClass)
    {
        if (itemRequestConverterClass.equals(CreatePartRequestConverter.class))
        {
            return new CreatePartRequestConverter();
        }
        return null;
    }
}

如果您还需要有关ItemRequest类的信息,方法签名可能会开始变得有点讨厌,并且需要更详细地分析 where 应如何提供或使用此类型信息。


编辑评论:

我认为在(编译时)类型检查方式中这是不可能的。这里的问题是,在您创建并返回新ItemRequestConverter时,您无法确定它是ItemRequestConverter,其类型参数为IR。或者反过来说:您无法在编译时检测到CreatePartRequestConverter的类型参数(即CreatePartRequest)与IR相同。

根据到目前为止讨论的代码片段,我认为在这种情况下应该 可以简单地进行转换。确保转换有效的责任留给实现“运行时类型检查”的人:

if (itemRequestClass.equals(CreatePartRequest.class))
{
    CreatePartRequestConverter result = new CreatePartRequestConverter();
    return (ItemRequestConverter<IR>) result;
}

因为没有什么能阻止你写作

//                          !!!
if (itemRequestClass.equals(SomeCompletelyDifferentRequest.class))
{
    CreatePartRequestConverter result = new CreatePartRequestConverter();
    return (ItemRequestConverter<IR>) result;
}

所以 应该有效:

interface ItemRequestConverter<IR extends ItemRequest>{}
interface ItemRequest{}
interface ItemRequestConverterFactory 
{
    public <IR extends ItemRequest> ItemRequestConverter<IR> 
        newInstance(Class<IR> itemRequestClass);
}

class CreatePartRequest implements ItemRequest {}
class CreatePartRequestConverter 
    implements ItemRequestConverter<CreatePartRequest> {}

class DefaultItemRequestConverterFactory implements ItemRequestConverterFactory 
{
    @Override
    public <IR extends ItemRequest> ItemRequestConverter<IR> newInstance(
            Class<IR> itemRequestClass)
    {
        if (itemRequestClass.equals(CreatePartRequest.class))
        {
            CreatePartRequestConverter result = new CreatePartRequestConverter();
            return (ItemRequestConverter<IR>) result;
        }
        return null;
    }
}

public class GenericFactoryTest
{
    public static void main(String[] args)
    {
        ItemRequestConverterFactory factory = null;
        ItemRequestConverter<CreatePartRequest> converter = 
            factory.newInstance(CreatePartRequest.class);        
    }
}