java - 从方法返回 Java 有界通用对象

标签 java generics inheritance

我知道 Oracle 教程和类似 How do I make the method return type generic? 的问题但我仍然无法从 Java 方法返回通用对象。

简要示例:我有一个网络 Packet 层次结构和一个 Handler 层次结构,参数化为它们处理的 Packet。最终,我有了一个 Handler注册表,其中包含一个方法,该方法会返回给定数据包的正确处理程序。

我想实现所有这些,理想情况下没有警告来手动抑制。

class Packet {}
class ThisPacket extends Packet {}
class ThatPacket extends Packet {}

interface PacketHandler<P extends Packet> {
    boolean handle(P p);
}

class ThisPacketHandler extends PacketHandler<ThisPacket> {
    boolean handle(ThisPacket p);
}

class ThatPacketHandler extends PacketHandler<ThatPacket> {
    boolean handle(ThatPacket p);
}

我相信这是很正常的,在我的实现中,我在中间有一些进一步的抽象类来塑造我的层次结构,但我认为现在可以忽略它。

关键部分是 i) 注册表:

class HandlersRegistry {
    static <<RETURN TYPE>> getHandler(Packet p) {
        if (p instanceof ThisPacket) return new ThisPacketHandler();
        if (p instanceof ThatPacket) return new ThatPacketHandler();
        return null;
    }
}

<<RETURN TYPE>> OPTIONS (I tried):
    // Raw-type Warning:
    A. PacketHandler 
    // the registry user won't be able to use the handler:
    B. PacketHandler<? extends Packet>
    // Type mismatch: cannot convert from 
    C. PacketHandler<Packet> 

..和 ii) 和注册表用户:

class HandlerSwitchExample {
    public static void main() {
        // [...]
        <<OBJECT TYPE>> handler = HandlersRegistry.getHandler(somePacket);
        handler.handle(somePacket);
    }
}

希望这个例子相当清楚。 感谢您提供任何有用的建议,甚至是完整的重新设计策略。

最佳答案

您基本上有两个平行的层次结构(PacketPacketHandler),其中一个层次结构中的每个级别都与另一个层次结构中的相同级别相关。下图显示了您的结构(跳过了 ThatHandler)

  Packet ------------> PacketHandler
    ^                        ^
    |                        |
ThisPacket --------> ThisPacketHandler

这些情况通常使用自引用类型参数来解决。此外,使用工厂方法而不是在注册表中创建对象。

这是你的类结构的变化(另外,我想你应该使 Packet 类抽象:

abstract class Packet<T extends Packet<T>> {
  /**
   *  Factory method.
   *  Override this method in sub-packets to return appropriate handlers
   */
  abstract PacketHandler<T> getHandler();
}

那么你的子数据包会是这样的:

class ThisPacket extends Packet<ThisPacket> {
  @Override
  PacketHandler<ThisPacket> getHandler() {
    return new ThisPacketHandlerImpl();
  }
}

class ThatPacket extends Packet<ThatPacket> {
  @Override
  PacketHandler<ThatPacket> getHandler() {
    return new ThatPacketHandlerImpl();
  }
}

现在,您的PacketHandlers(此处不需要单独的处理程序接口(interface)):

interface PacketHandler<P extends Packet<P>> {
  boolean handle(P p);
}

class ThisPacketHandlerImpl implements PacketHandler<ThisPacket> {
  @Override
  public boolean handle(ThisPacket p) {
    return false;
  }

}

class ThatPacketHandlerImpl implements PacketHandler<ThatPacket> {
  @Override
  public boolean handle(ThatPacket p) {
    return false;
  }
}

最后是注册表:

class HandlersRegistry {
  static <P extends Packet<P>> PacketHandler<P> getHandler(P p) {
    return p.getHandler();
  }
}

然后像这样使用它:

ThisPacket somePacket = new ThisPacket();
PacketHandler<ThisPacket> handler = HandlersRegistry.getHandler(somePacket);
handler.handle(somePacket);

现在,有了上面的结构,你可以继续添加新的数据包,而不需要修改现有的类。只需创建一个 Packet 和相应的 PacketHandler。在新的 Packet 类中覆盖 getHandler() 方法,您就可以使用它了。现在还需要更改注册表类。

关于java - 从方法返回 Java 有界通用对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29119731/

相关文章:

java - <U, T extends U> 和 <T, U super T> 不一样吗?

c++ - 如何让 Doxygen 忽略继承关系?

oop - Go 中是否存在脆弱的基类问题?

java - 使用 Gradle 构建 Kotlin + Java 9 项目

java - 可以使用泛型 Java 方法的泛型类型来强制执行参数类型吗?

java - 为什么 Spring 使用 ForkPoolJoin 而不是带有 @Async 的 ThreadPoolTask​​Executor?

generics - 错误 : Expected Type Parameter, 发现关闭

c++ - 什么是对象切片?

Java - 将 byte[] 转换为 char[]。编码是UTF-16

java - ?不会替换为 $$ 中的值