【问题标题】:Changing a return type depending on the calling method根据调用方法更改返回类型
【发布时间】:2009-05-28 05:45:53
【问题描述】:

基本上我想要的是两个返回值略有不同的公共方法来调用相同的方法来完成任何需要的工作。它们都返回私有方法的返回值,但是私有方法会根据调用它的公共方法知道如何返回正确的值。

示例方法:

public Map<Type1, Type3> doSomething1();
public Map<Type2, Type3> doSomething2();

private Map<Type1/Type2, Type3> doSomething(); 

因此,在上面的示例中,doSomething() 返回 Type1 或 Type2 作为 Map 的键类型,具体取决于调用它的公共方法。它将能够执行简单的检查,并使用正确类型的对象填充地图。

也许这可以通过一些巧妙的 Java 反射来完成?我不知道。这一切似乎都很狡猾,所以如果有更好的方法来解决这个问题,我会全力以赴。

【问题讨论】:

    标签: java generics reflection return-value typing


    【解决方案1】:

    我强烈建议在这里避免使用反射魔力。一个函数必须正确地做一件事,并且不能依赖于谁调用它。

    更好的方法是将 doSomething() 重构为更小的函数,创建两个名为 doSomethingFor1() 和 doSomethingFor2() 的新函数。这两个函数都可以重用旧 doSomething() 的重构部分。

    现在调用 doSomething1() 并使用 doSomethingFor1()。

    同样,doSomething2() 应该使用 doSomethingFor2()。

    干杯,

    jrh.

    【讨论】:

    • 是的,这也是我想出的。我同意一个方法不应该依赖于它的调用者。但是,如果 doSomethingFor1() 和 doSomethingFor2() 共享完全相同的代码,唯一的区别是它们添加了哪个对象作为地图的键呢?这不会是代码的大量重复吗?
    • 必须通过适当地重构函数并将重复代码放置在常用函数/方法中来应对重复。
    • @The Dissonant:所以使用参数来指示要添加哪个键。不要从谁给你打电话来推断。
    【解决方案2】:

    请注意: 我误解了这个问题,所以这个答案与问题的要求相反。我将把它作为社区 wiki 留作参考,但这并不能回答最初的问题。

    如果Type1Type2 有一个共同的子类型称为SuperType,那么说第一个类型是? extends SuperType 就可以了。

    这里有一个小例子,使用IntegerDouble 作为两种类型,它们的共同祖先是Number

    private Map<Integer, String> doSomethingForInteger() {
      HashMap<Integer, String> map = new HashMap<Integer, String>();
      map.put(10, "Hello");
      return map;
    }
    
    private Map<Double, String> doSomethingForDouble() {
      HashMap<Double, String> map = new HashMap<Double, String>();
      map.put(3.14, "Apple");
      return map;
    }
    
    public Map<? extends Number, String> doSomething(boolean b) {
      if (b)
        return doSomethingForInteger();
      else
        return doSomethingForDouble();
    }
    

    这里,doSomething 方法将返回两种类型的 HashMaps,具体取决于传入的 booleanHashMap&lt;Integer, String&gt;HashMap&lt;Double, String&gt;doSomething 方法返回。

    实际上用boolean 调用doSomething 可以这样完成:

    Map<? extends Number, String> map1 = doSomething(true);
    Map<? extends Number, String> map2 = doSomething(false);
    

    map1 将以 Hashmap&lt;Integer, String&gt; 结尾,而 map2 将得到 Hashmap&lt;Double, String&gt;

    【讨论】:

    • 我很欣赏这个答案,但你的答案是错误的。我不希望超类型方法成为公共方法,并且我希望所有地图实例化/操作的东西都只能在一个私有方法中完成(即没有重复)。
    【解决方案3】:

    如果一切都失败了,让私有方法返回 Object 并在公共方法中使用强制转换。

    【讨论】:

      【解决方案4】:

      第一个问题是为什么需要这种精确的结构。

      但安全的方法是让它返回

      public Map<Object, Type3> doSomething();
      

      如果 Type1 和 Type2 没有共同的超类型。如果你确实有一个通用的超类型,你可以使用它来代替 object。

      最好重构不需要的代码。

      【讨论】:

      • 我想知道,doSomething() 怎么知道要添加为 Map 键的 Object 的哪个子类(即 Type1 或 Type2)?它需要能够执行检查。
      【解决方案5】:

      我需要您的问题中缺少的一些信息,例如如何实例化 type1 和 type 2,因为您不能直接从任意类型参数实例化。现在,我们假设有一些公共数据用于实例化 type1 和 type2。否则,没有充分的理由对两种方法都使用一种方法。在后一种情况下,这意味着一个函数根据类型做两件不同的事情,这是不好的编程。如果您要拥有直接基于调用方法的逻辑,只需拥有两个私有方法并重构出常用的东西。

      如果您只是根据一些数据进行不同的实例化,那么最简单的方法是声明一个私有内部接口:

      private interface Instantiator<T> {
      
           T getNew(Data data);        
      
      }
      

      现在,假设您可以实例化您的类型,您实际上可以使用它:

      private <T> Map<T,Type3> doSomething(Instantiator<T> instantiator) {...}
      

      作为方法签名,并让公共方法使用适当的 Instantiator 实现来调用它。

      【讨论】:

        【解决方案6】:

        您绝对可以通过使用反射分析堆栈来做到这一点。但我会尽量避免它:

        • 返回基类型(或对象)并在调用者中正确转换,无论如何您都必须这样做
        • 将参数传递给私有方法,以某种方式指示要做什么并返回

        【讨论】:

          【解决方案7】:

          您可以模拟 Closure 的想法:

          interface MappingClosure {
              public void map(Map, MapProvider);
          }
          


          class Caller implements MappingClosure {
               public void map(final Map MAP, final MapProvider CALLEE) {
                   this.MAP = specialise(MAP);
                   // CALLEE USED AS KEY
               }
          }
          


          class MapProvider {  
              public Map getMap(final MappingClosure CALLER) {
                  return CALLER.map(mapInstance, this);
              }
          }
          

          然后修改数据以适应对象的需要与使用需要它的对象的方法不同。

          【讨论】:

            猜你喜欢
            • 2018-03-22
            • 1970-01-01
            • 1970-01-01
            • 2013-04-24
            • 1970-01-01
            • 2021-11-16
            • 2011-11-09
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多