【问题标题】:Method that returns different types?返回不同类型的方法?
【发布时间】:2015-09-03 09:34:59
【问题描述】:

我正在写一个方法。

这是层次结构树:

IProtocoll
|
|--ProtocolImpl1
|
|--ProtocolImpl2
|
|--ProtocolImpl3

方法本身如下所示:

public static List<IProtocol> getProtocolsByType(String type, Transaction trx) {
    Iterator<IProtocol> protocols = trx.getProtocols();
    List<IProtocol> protocolsList = new ArrayList<IProtocol>();
    while (protocols.hasNext()) {
        if (StringHeper.isEqual(protocolls.next().getProtocolType(), type) {
            protocolsList.add(protocolls.next());
        }
    }
    return protocolsList
}

以及用法示例。

List<IProtocol> list = ProtocolHelper.getrProtocolsByType("PROTOCOL1", trx)

for (IProtocol protocol : list) {
    ProtocolHelper.createProtocolType1((ProtocolImpl1) protocol)
}

现在 - 从类型层次结构中可以看出 - 此方法可能返回 3 种可能性。

String type 定义应返回的协议类型。 trx.getProtocols() 将返回一个包含所有 3 种协议类型的迭代器。

有没有办法以某种方式统一此方法,使其返回这 3 种类型中的一种,而无需稍后在使用该方法时使用不必要的强制转换?

【问题讨论】:

  • 如果您觉得需要将具有接口类型的对象转换为其实现,那应该敲响警钟。您的抽象可能不正确,通过更改接口,您可以完全避免强制转换。 (当然这并不总是可能的,但值得检查。)
  • 只是您发布的代码的旁注:您在循环中调用了两次protocolls.next(),因此可能会跳过元素。请注意,next() 会将迭代器前移 1,因此如果您想重用该元素(例如,在 if 子句中,然后将其添加到列表中),则需要存储返回值。

标签: java collections iterator


【解决方案1】:

您可以尝试以下方法:

public static <T extends IProtocol> List<T> getProtocolsByType(Class<T> typeClass, Transaction trx) {    
  Iterator<IProtocol> protocols = trx.getProtocols();
  List<T> protocolsList = new ArrayList<T>();
  while( protocols.hasNext() ) {
     //call next() only once
     IProtocol p = protocols.next();

     //Check if p is an instance of typeClass or a subtype
     if ( typeClass.isAssignableFrom( p.getClass() ) {
        protocolsList.add( (T)p );
     }
   }
   return protocolsList;
}

List<ProtocolImpl1> list = ProtocolHelper.getrProtocolsByType( ProtocolImpl1.class, trx)

因此,不是将类型作为字符串传递,而是传递您想要获取的实现类。

强制转换 (T)p 是必要的,但因为您检查 p 是否属于 T 类型或子类型,所以这是安全的。

【讨论】:

  • 请注意,调用者可能应该使用:List&lt;? extends IProtocol&gt; protocolType = getProtocolsByType(..)。由于返回的集合可以充当IProtocol 实例的生产者
  • 将其分配回List&lt;T&gt;?
  • @TheLostMind 如果我正确理解了 OP,他不想使用它,因为您必须再次转换为实际类型。 List&lt;? extends IProtocol&gt; 只会将元素公开为 IProtocol 类型,但 OP 似乎想要 List&lt;ProtocolImpl1&gt; 等。
  • 你不认为 OP 应该使用 IProtocol 调用覆盖的方法吗?如果IProtocol 及其实现类的合同很好,那么 OP 应该这样做。如果他需要其他方法,那么可能得到一个具体的类集合就可以了
  • @TheLostMind 是的,没错。如果您只能使用IProtocol,那么您绝对应该这样做。
【解决方案2】:

泛型是救星。使用这样的东西:

public static <T extends IProtocol> List<IProtocol> getProtocolsByType(Class<T> clazz, Transaction transaction) {    
  //do logic here
}

【讨论】:

    【解决方案3】:

    这是一个可能的解决方案:

    public <I extends IProtocol> List<I> getProtocols(Class<I> protocolClass) {
        Iterator<IProtocol> protocols = trx.getProtocols();
        List<I> protocolsList = new ArrayList<I>();
        while (protocols.hasNext()) {
          if (protocols.next().getClass().equals(protocolClass)) {
              protocolsList.add((I) protocols.next());
          }
        }
        return protocolsList;
    
    }
    

    不要将类型指定为字符串,而是将其指定为类。有了上面的签名,你就不需要投射了。

    唯一的问题是对 I 的强制转换会导致警告,但由于我们已经检查了类类型,我们知道它会强制转换。

    【讨论】:

      【解决方案4】:

      你可以这样使用它:

      List<ProtocolImpl1> list = (List<ProtocolImpl1>) ProtocolHelper.getProtocolsByType("PROTOCOL1", trx)
      
      for (ProtocolImpl1 protocol : list) {
          ProtocolHelper.createProtocolType1(protocol)
      }
      

      如果您还想避免这种转换,根据您当前的代码,我看到的唯一方法是在 ProtocolHelper 中创建单独的方法:

      List<ProtocolImpl1> getAllProtocolsOfType1(trx);
      List<ProtocolImpl2> getAllProtocolsOfType2(trx);
      List<ProtocolImpl3> getAllProtocolsOfType3(trx);
      

      当然,如果协议数量增加,那当然不是很可扩展。

      【讨论】:

        【解决方案5】:

        尝试使用 java 泛型。 public static &lt;T extends IProtocol&gt; List&lt;T&gt; getProtocolsByType 类型 T 可以是任何扩展 IProtocol 的类型。 查看有关它们的 oracle 教程 -> https://docs.oracle.com/javase/tutorial/java/generics/ 他们会解决你的问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多