【问题标题】:Java - Factory Method that returns generic Base typeJava - 返回通用基本类型的工厂方法
【发布时间】:2012-06-23 18:29:14
【问题描述】:

我正在尝试通用化返回的工厂方法 一个通用的基类。它有效,但我得到了 “BaseClass 是原始类型...”警告。

我已阅读有关通用方法的 Java 文档, 但我仍然不完全了解如何做到这一点。

这里有一些代码:

第一课

//base abstract class
public abstract class BaseFormatter<T>
{
    public abstract String formatValue(T value);
}

类#2

//two implementations of concrete classes
public class FooFormatter extends BaseFormatter<Integer>
{
    @Override
    public String formatValue(Integer value)
    {
        //return a formatted String
    }
}

第三课

public class BarFormatter extends BaseFormatter<String>
{
    @Override
    public String formatValue(String value)
    {
        //return a formatted String
    }
}

工厂方法在一个单独的类中

public static BaseFormatter getFormatter(Integer unrelatedInteger)
{
    if (FOO_FORMATTER.equals(unrelatedInteger))
        return new FooFormatter();
    else if (BAR_FORMATTER.equals(unrelatedInteger))
        return new BarFormatter();
    //else...
}

从代码中的其他地方调用工厂方法

BaseFormatter<Integer> formatter = getFormatter(someInteger);
formatter.formatValue(myIntegerToFormat);

问题是 getFormatter() 方法警告 BaseFormatter 是 一个原始类型,它就是。我已经尝试过各种东西,比如 BaseFormatter 等。我当然希望返回类型是通用的,如声明的 BaseFormatter 在调用方法中。

请注意,格式化程序类型不基于类类型。例如不是所有的整数 值使用 FooFormatter 格式化。有两三个不同的 可以格式化整数(或字符串或列表)的方式。这就是 参数 unrelatedInteger 用于。

提前感谢您的任何反馈。

【问题讨论】:

  • 简单的答案:Java 类型系统无法安全地表达您想要的约束。这意味着您无法摆脱此演员表的警告。

标签: java generics


【解决方案1】:

如果在 BaseFormatter 中定义了 getFormatter,则使用:

public static BaseFormatter<T> getFormatter(Integer unrelatedInteger)

如果 getFormatter 定义在 BaseFormatter 以外的其他类中,则使用:

public static BaseFormatter<?> getFormatter(Integer unrelatedInteger)

【讨论】:

  • 如果我做 BaseFormatter,我必须这样做:public static BaseFormatter getFormatter(Integer converter)。我不能这样做,因为 return new FooFormatter() 会导致错误。无法从 FooFormatter 转换为 BaseFormatter,所以这不起作用。
  • 我阅读了您的更新。这就是问题所在:getFormatter 是在另一个类中定义的。如果我返回一个未知类型的 BaseFormatter (BaseFormatter>),则此方法很高兴。但是在调用方法中,我不能做 BaseFormatter formatter = getFormatter(someInteger);我收到类型不匹配错误。如果我将其更改为 BaseFormatter> formatter = getFormatter(someInteger);那么我不能传入一个整数,因为类型是未知的,而不是整数。
  • @TedJones 您能否编辑您的问题,将每个课程按原样(单独)发布,而不是像您所做的(合并)一样,因为很难看出谁是谁以及谁在打电话给谁
【解决方案2】:

您实际上是在说BaseFormatter 的类型化参数与作为参数传递给getFormatter 方法的unrelatedInteger 之间没有联系。

我收到其他警告:

Uncehcked Assignment: BaseFormatter to BaseFormatter<Integer>

此警告比您指出的更严重。它警告此用户代码可能会尝试将 BaseFormatter&lt;String&gt; 插入到 BaseFormatter&lt;Integer&gt; 中,只有在运行时失败时才会注意到这一点......假设用户不小心使用了您的工厂方法,如下所示:

BaseFormatter<Integer> myUnsafeFormatter =
        FormatterFactory.getFormatter(unrelatedIntegerForBarFormatter);

编译器无法将unrelatedInteger 与返回的BaseFormatter 的参数化类型相关联。

另外,我会让用户明确地使用具体的格式化程序构造函数。所有格式化程序共享的任何通用代码都可以放入FormatterUtils 类(只是不要让那个 utils 类增长太多......)。

【讨论】:

    【解决方案3】:

    学术语言中的某些类型系统可以表达所谓的依赖和。 Java当然不能;那么,明智地,getFormatter 方法返回的对象的类型可能是什么?我们能做的最好的就是BaseFormatter&lt; ? extends Object &gt;,或者简称BaseFormatter&lt; ? &gt;,因为IntegerString只有Object有共同点。

    我认为原始帖子引出了一个问题,为什么我们必须使用整数来决定返回什么格式化程序,如果调用者不知道格式化程序的类型,为什么调用者需要比 @ 更强的变量类型987654326@?

    【讨论】:

    • 嗯,从技术上讲,它只需要 BaseFormatter>。问题在于它使用 BaseFormatter 作为各种接口,使用适当的数据类型调用相同的 format() 方法。在它采用 Object 并将其转换为正确的类型之前。这当然是一个问题,因为它对类转换异常开放。在对其进行泛化时,在 format(arg) 方法上强制使用数据类型是合理的。由于不同的格式化程序采用不同的类型,我不得不在超类中使用 T 。我能想到的唯一其他选择是(继续下一篇文章)
    • 替换 BaseFormatter formatter = getFormatter(someInteger);使用 if 语句并实例化正确的格式化程序。它在几个地方被调用,所以这很蹩脚。我将该代码放在一个公共位置。但是要使 FooFormatter 和 BarFormatter 工作相同(例如,相同的方法调用,不同的 argtype),它需要一个具有抽象方法的超类都必须实现。我正在考虑的另一个解决方案是使用 CommonFormatter 和重载 format(),所以我可以执行 cf.format(unrelatedInteger, myIntToFormat, cf.format(unrelatedInteger, myStrToFormat)。(下一篇文章继续)
    • 因为我可以有几种不同的格式(有超过 2 种,但在本例中我保持为 2),这些方法中的每一种都会有一系列 if 语句。例如if (FOO_FORMATTER.equals(unrelatedInteger)) //do foo formatting; else if (BAR_FORMATTER.equals(unrelatedInteger)) //do bar formatting我一点也不喜欢。我愿意接受任何人的任何建议。
    猜你喜欢
    • 1970-01-01
    • 2018-07-01
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    • 1970-01-01
    • 2016-12-24
    • 2021-07-28
    • 1970-01-01
    相关资源
    最近更新 更多