Java 具有多个泛型的泛型工厂模式

Java generics Factory Pattern with multiple Generics

我正在尝试学习如何使用泛型,但我很难实现工厂模式。我希望我的 DataFactory 接口有一个方法,该方法 returns 一个扩展数据的 class 的对象。我相信下面的代码会起作用,但我很难理解某些东西。有没有办法避免在 DataFactory 接口中显式指定第二种类型? Message extends Data,所以如果 T extends Data,难道不应该隐含 U 吗?

数据class:

public abstract class Data<T> {

    private final long id;
    private final T content;
    private final User sender;
    ...
}

留言class:

public class Message extends Data<String> {
    ...
}

数据工厂接口:

public interface DataFactory<T extends Data<U>, U> {
    T newInstance(U content, User sender);
}

消息工厂Class:

public class MessageFactory implements DataFactory<Message, String> {

    @Override
    public Message newInstance(String content, User sender) {
        return new Message(content, sender);
    }
}

为什么我不能只写:

public class MessageFactory implements DataFactory<Message>

很抱歉,如果这个问题措辞不当,我不确定如何表达。最初我不想将类型参数添加到 class 本身,只是添加到方法中,但我在尝试使其工作时遇到了更多问题。我什至不确定我是否正确实施了这一点。任何帮助将不胜感激。

因为类型系统本身不知道,一般情况下,你不会写GenericData<T> extends Data<T>。在这种 specific 情况下,您的 Message class 具有针对通用类型的特定 class,但您可以提供其他不会提供的参数。

即使 OP 已经选择了一个答案,我还是想分享额外的相关信息,以帮助其他人来这里寻找答案。

为什么要使用泛型?

首先,我们首先需要了解使用泛型的原因是什么。 通用类型参数为您提供了一种使用不同输入重复使用相同代码的方法。例如,您可以使用通用代码来处理一组字符串,或者一组具有相同代码的小部件。在泛型出现之前,我们处理类似情况的方式是转换对象。为了简化,让我们使用 OP 示例并使 Data class 非抽象。

public void doSomethingWithThisInput (Object o) {
    if (o instanceof MyClass) {
        MyClass myCls = (MyClass) o;
        // do something here
    }
}

如果您在泛型之前处理过 Java 集合,您就会知道这曾经是多么痛苦。旧方法的部分问题在于,在许多情况下,您没有在开发过程中发现转换问题。这些案例中几乎 100% 都是在运行时发现的,每个人都认为这是非常糟糕的。使用泛型,这些对象不兼容问题会在编译时被发现。

泛型的用例

您想要使用泛型的主要原因是在 class 中创建相似“事物”的集合。这样的例子可以在 Java 语言中找到 SetListMap

public abstract class Data<T> {
    private T content;
    // other methods and attributes omitted;
}

有了这样一个class,你就可以泛指Data对象的内容了。数据内容实际上可以是任何内容:一个 Email 对象、一个 File 对象,或者只是一个 String。显然,这里的意图是如果你有一个数据内容的集合,每个对象应该是相同的类型。创建不同内容的集合毫无意义,而且实际上适得其反。

PECS

这可能是您需要学习如何正确使用泛型的最重要的一课。 **PECS** 是 Producers Extend Consumers Super 的缩写。这是什么意思?我能给你的最佳答案可以在这里找到 [ link 是关于 PECS 的答案。

额外资源

Oracle Java Lesson: Generics