如何在不需要强制转换的情况下获得实现通用接口的特定类的工厂?

时间:2012-09-14 12:25:11

标签: java generics factory

所以我得到了一个接口SuperType和一堆实现类TypeATypeB等等。我还有一个顶级接口,它有一个参数化方法:

public interface UsedByProductThing<T extends SuperType> {
    public T doStuff(T one);
}

我有一个工厂(见下文),生成实现GeneralProduct的对象:

public interface GeneralProduct<T extends SuperType> {
    T doSomething(T input);
}

以下是实施ProductA

public class ProductA implements GeneralProduct<TypeA> {
    UsedByProductThing<TypeA> in;

    public ProductA(UsedByProductThing<TypeA> in) {
        this.in = in;
        in.doStuff(new TypeA());
    }

    @Override
    public TypeA doSomething(TypeA input) {
        return null;
    }
}

现在有问题的工厂:

public class GeneralFactory {
    public static <T extends SuperType> GeneralProduct<T> createProduct(
            int type, UsedByProductThing<T> in) {
        switch (type) {
        case 1:
            return (GeneralProduct<T>) new ProductA((UsedByProductThing<TypeA>) in);
            // at this point, i want to return a "new ProductA(in)" preferably
            // without casting
            // or at least without the cast of the argument.
        default:
            throw new IllegalArgumentException("type unkown.");
        }
    }
}

如评论所述,我希望该工厂方法不使用强制转换。我知道返回类型必须是GeneralProduct,但我想不出省略强制转换的方式(它也给了我一个“未经检查的强制转换” - 警告)。而且,我想不出一种省略论证演员的方法。如果有必要摆脱那个地方的“不安全”铸造,我能够重组整个代码。你能告诉我一种在这里好看又顺畅的方法吗?

此外,请根据您的喜好编辑我的问题 - 我不知道如何在标题中正确解决问题。

非常感谢!

3 个答案:

答案 0 :(得分:4)

你无法避免施放,因为

  • 您的in类型UsedByProductThing<T>要转换为UsedByProductThing<TypeA>且编译器无法知道TTypeA
  • ProductA是GeneralProduct<TypeA>,编辑器也不知道此处TTypeA

避免强制转换的唯一方法是将T替换为TypeA

    public static GeneralProduct<TypeA> createProduct(
            int type, UsedByProductThing<TypeA> in) {
        switch (type) {
            case 1:
                return new ProductA(in);
            default:
                throw new IllegalArgumentException("type unkown.");
        }
    }

答案 1 :(得分:0)

我不确定有什么干净的方法可以做到这一点。此外,我认为任何投射你正在做的方式本质上都是不安全的,因为有人可以传递一个与“in”值不兼容的“类型”值。

话虽如此,在处理泛型时,这些固有的未经检查的演员阵容很常见。如果可能的话,你应该避免使用它们,但有时你不能,并且应该只添加注释来抑制你是否真的只想摆脱编译器警告。

@Suppress( “未登记”)

或者,为什么不采取建设者的方式?

public inteface Builder<T extends SuperType> {
    public GeneralProduct<T> createProduct(UsedByProductThing<T> thing);
}

public class BuilderFactory {
    public static <T extends SuperType> Builder<T> createBuilder(Class<T> clazz) {
       if (clazz.equals(ProductA.class)) {
          return new (Builder<T>) ProductABuilder();
       }
       ...
    }
}

然后使用它(假设您已经创建了一个构建器实现:

Builder<ProductA> builder = BuilderFactory.createBuilder(ProductA.class);
UsedByProductThing<ProductA> thing = ...;
ProductA product = builder.createProduct(thing);

答案 2 :(得分:0)

不要返回

"GeneralProduct<T>"

,更好的回归

"GeneralProduct<?>"

,所以不需要投射结果。

但无论如何,你必须为“ProductA”投射参数!