【问题标题】:Java Higher Order Polymorphic FunctionJava 高阶多态函数
【发布时间】:2013-01-24 16:44:13
【问题描述】:

我非常熟悉 Scheme 和 Haskell 等函数式语言。我正在尝试解决 Java 中的一个问题并且正在苦苦挣扎,可能是因为我仍然处于功能性思维模式。

我想写:

public void doQueryAndStoreData(String query, <? extends Collection> storeIn) {
    /* make a jdbc query, get ResultSet */
    ResultSet rset = ...;
    ProcessResultSet proc = new ProcessResultSet();
    proc.process(rset, storeIn);
    /* clean up */
}

界面如下:

private interface IProcessResultSet<C> {
    public void process(ResultSet rset, C storeIn);
}

和一个实现接口的类,如:

private class ProcessResultSet implements IProcessResultSet<? extends Collection> {
    public void process(ResultSet rset, Map storeIn) {
        /* do something */
    }

    public void process(ResultSet rset, List storeIn) {
        /* do something else */
    }
}

这样第一个方法可以根据给出的storeIn 的类型调用适当的process

我可以在 Haskell 中编写

class Storeable c a where
    store :: a -> c a -> c a

doQueryAndStoreData :: Storeable c a => ResultSet a -> c a -> c a
doQueryAndStoreData (ResultSet rs) coll = foldr store coll rs

并为我想在其中存储ResultSet 的任何集合类型提供Storeable 实例。

这是 Java 中的正确方法吗?因为我觉得我在与语言作斗争来实现这一点。

【问题讨论】:

  • 我认为您需要的可以使用访问者模式来解决 - 双重调度。
  • 就个人而言,我更倾向于从函数中返回一些东西。倾向于使代码更具可读性。想不出最接近 Map 和 List 的超类型,但那将是返回值,然后在赋值语句中强制转换为 Map/List,即 `Map myMap = new Map; myMap = (Map) process(rset, myMap);"

标签: java polymorphism higher-order-functions


【解决方案1】:

不,Java 不这样做。

您需要执行以下操作:

public <T> void doQueryAndStoreData(
    String query,
    T storeIn,
    ResultSetProcessor<T> processor
) {

或者更有可能:

public void doQueryAndStoreData(
    String query,
    ResultSetHandler handler // may contain processor and storeIn
) {

我希望我不需要提到 SQL 注入漏洞是一件坏事。 (另外Map 不是 Java 中的 Collection(它在 C# 中,但 C# Collection 不是很有用)。

【讨论】:

    【解决方案2】:

    很遗憾,您不能这样做。编译器必须在编译时知道这个调用绑定到哪个方法。如果你想根据对象的运行时类型来决定调用哪个方法,你必须手动检查:

    你能做的最多:

    private class ProcessResultSet implements IProcessResultSet<? extends Collection> {
    
        @Override
        public void process(ResultSet rset, Collection storeIn) {
            if (storeIn instanceof Set) {
                return processSet(rset, (Set) storeIn);
            } else if (storeIn instanceof List) {
                return processList(rset, (List) storeIn);
            } else {
                throw new IllegalArgumentException("Unimplemented storage type");
            }
        }
    
    
        public void processSet(ResultSet rset, Set storeIn) {
            /* do something */
        }
    
        public void processList(ResultSet rset, List storeIn) {
            /* do something else */
        }
    }
    

    【讨论】:

      【解决方案3】:
      private class ProcessResultSet implements IProcessResultSet<? extends Collection> {
      
          public void process(ResultSet rset, Object storeIn) 
          {
              if ( storeIn instanceof Map)
                  processMap(rset,(Map) storeIn);
              else if (storeIn instanceof List)
                  processList(rset,(List) storeIn);   
              else
                  System.out.println("Unsupported input type.");
          }
      
          public void processMap(ResultSet rset, Map storeIn) {
              /* do something */
          }
      
          public void processList(ResultSet rset, List storeIn) {
              /* do something else */
          }
      }
      

      【讨论】:

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