具有泛型类型的Java工厂

时间:2019-03-10 18:31:18

标签: java generics

我正在为我的大学做一个项目,但遇到了问题。

基本上,该项目由一个客户端-服务器应用程序组成,我想为通信创建一个Packet类。该数据包由标题和正文组成。现在有问题了。我可以有一些不同的主体,但是它们都继承了泛型类Body。

我的想法是制作一个这样的Packet类:

public class Packet <T extends Body>{
    private Header header;
    private T body;
}

和这样的Header类:

public class Header {
    private OPS op;
}

现在,我想拥有一种工厂,当我从服务器的主体调用方法Factory.createPacket()时,它将以这种方式构建Packet:

  1. 从SocketChannel读取标题
  2. 基于标头的字段,它将读取该类型的正文

例如,如果读取标头上的CREATE(一种OPS)操作,则应读取CreateBody(继承Body)

此外,每个主体都必须具有允许从SocketChannel获取该类型的主体的功能,这就是我认为使用泛型的原因。

有人可以告诉我更好的方法吗?

谢谢大家!

1 个答案:

答案 0 :(得分:1)

不确定您是否真的要在此处使用泛型。如果您全力以赴,这只会对您有所帮助。如果走这条路,您的最终目标应该是依靠编译器来检测何时将某些Header与错误的Body类型混合使用。这意味着Header也应参数化。

您的Header最终是决定Body类型的人。由于它嵌入了这些知识,因此最好是将这些信息实际提供给类型系统,即Header<T extends Body>

要使其正常工作,您需要基于T实例,从标题中找出此类型OPS。因此OPS本身就必须是参数化类型。

如果OPSenum,则无法对其进行参数化,因此无法以类型安全的方式进行操作(即,在某些时候没有显式强制转换);所以您必须添加类似的方法:

Class<? extends Body> bodyType();

因此,每个OPS实例都将在内部绑定到主体类型(但是您不能这样使它可见)。有人需要将其转换为特定的身体类型。那可能就是您的Header

class Header<T extends Body> {
    private final Class<T> bodyType;
    public Header(OPS ops) {
        // any type-safety feeling gets blown here!
        this.bodyType = (Class<T>) ops.bodyType();
    }
    // ...
}

确保其安全的唯一方法是将OPS本身参数化为OPS<T extends Body>并手动实例化每种OPS类型(因为枚举不支持此操作)。


如果这看起来很麻烦,那是故意的。它的主要目的是阻止您使用泛型,因为我猜您真的不需要它们。为了验证这一点,请在代码中寻找任何声明为Packet<SpecificBodyType>的引用,如果仅仅是Packet就无法使用。

鉴于您可以将任何Body子类型视为顶级Body抽象,因此OPS可以(内部)绑定到特定的Body子类。如上所述:Class<? extends Body> bodyType();。因此,您可以在实际需要的地方在运行时使用特定的类

或者,OPS可以是Function<SocketChannel, Body>,因此它将自行决定在每个Body实现中使用哪种apply()子类型。但是,如果满足以下条件,则程序中的其他任何人都不必关心具体的Body子类型:

  1. 在编译时实际上并不需要它们
  2. 我们不费吹灰之力将代码重构为OPS类型和主体类型之间的链接,供编译器检查。