【问题标题】:Create generic factory with generic subtype object in Java在 Java 中创建具有泛型子类型对象的泛型工厂
【发布时间】:2014-03-07 09:42:54
【问题描述】:

我用 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”。

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

【问题讨论】:

    标签: java generics inheritance factory


    【解决方案1】:

    您似乎在类型参数和它们应该实际表示的类型之间存在不匹配:您将Class&lt;IR&gt; 传递给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 类的信息,方法签名可能会开始变得有点讨厌,并且必须更详细地分析 wherehow 应该提供或使用这种类型的信息。


    编辑评论:

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

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

    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);        
        }
    }
    

    【讨论】:

    • 这不是我想要实现的。我的目标是:ItemRequestConverter&lt;CreatePartRequest&gt; converter = factory.newInstance(CreatePartRequest.class).
    • 我已经提出过类似的问题。一个演员是必要的。主要原因可能是类型擦除。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多