重构Java代码以使其可重用

时间:2017-10-26 02:21:28

标签: java refactoring

我最近创建了一个简单的方法,它将HashMap和LinkedList作为参数。它遍历HashMap,找到遵循这些规则的任何两个条目:

  1. 此条目的键的总和必须可被100整除
  2. 密钥总和必须小于1000
  3. 如果具有相同值的条目多次出现,则应跳过该案例
  4. 遵循这些规则的对将添加到LinkedList。它看起来像这样:

    private static void compare2(HashMap<Integer,String> values,List<String>results){
        if (values.size()>1) {
            for(HashMap.Entry<Integer,String> entry1:values.entrySet()){
                for (HashMap.Entry<Integer,String> entry2:values.entrySet()){
                    if (entry1.getValue().equals(entry2.getValue()))continue;
                    if ((entry1.getKey() + entry2.getKey())%100 == 0 && (entry1.getKey() + entry2.getKey())<1000){
                        results.add(entry1.getKey() + "+" + entry2.getKey() + "=" + entry1.getKey() + entry2.getKey());
                        results.add(entry1.getValue());
                        results.add(entry2.getValue());
                    }
                }
            }
        }
    }
    

    现在我想创建类似的方法,找到遵循相同规则的3个条目。问题是我想重用现有的代码而不是复制/粘贴这个和modyfiyng,我似乎无法找到一种方法来做到这一点。如果我需要改变我的方法,我不介意,只要结果是相同的。

2 个答案:

答案 0 :(得分:1)

您可以将数字量设为参数:N。

您可以继续使用for循环,但另一种示例方法可能是使用lambda&stream和stream重构您的方法,如下所示:

List<List<Map.Entry<Integer, String>>> compareN(HashMap<Integer, String> map, int n) {
    return map.entrySet().stream()
              .map(entry -> listOfNAccompanyingEntriesThatSatisfyTheConditions(entry, emptyList(), map, n - 1))
              .filter(list -> !list.isEmpty())
              .collect(toList());
}

方法listOfNAccompanyingEntriesThatSatisfyTheConditions是递归方法:

private List<Map.Entry<Integer, String>>
                listOfNAccompanyingEntriesThatSatisfyTheConditions(Map.Entry<Integer, String> newEntry,
                                                                   List<Map.Entry<Integer, String>> selectedEntries,
                                                                   HashMap<Integer, String> originalMap,
                                                                   int n) {

        List<Map.Entry<Integer, String>> newSelectedEntries = join(newEntry, selectedEntries);

        if (n == 0) return satisifiesCondition(newSelectedEntries) ? selectedEntries : emptyList();

        return originalMap.entrySet().stream()
                          .filter(entry -> !selectedEntries.contains(entry) && !entry.equals(newEntry))
                          .map(entry -> listOfNAccompanyingEntriesThatSatisfyTheConditions(entry, newSelectedEntries, originalMap, n - 1))
                          .flatMap(Collection::stream)
                          .collect(toList());
    }

对于每个 n ,该方法会在原始完整列表中再次拍摄,以累积可能满足要求的子列表。如果达到了数量(n == 0),则递归停止并验证停止条件:

private static boolean satisifiesCondition(List<Map.Entry<Integer, String>> entries) {
    int sum = sumOfTheKeysFrom(entries);
    return sum % 100 == 0 && sum < 1000;
}

但是,这种方法实际上是对您的实现的精确翻译,并且仍然存在同样的问题。例如,如果您为

运行它
HashMap<Integer, String> map = new HashMap<Integer, String>() {{
        put(1, "fred");
        put(2, "anja");
        put(24, "tom");
        put(45, "eddy");
        put(22, "lenny");
        put(77, "tommy");
        put(55, "henry");
        put(43, "alfred");
    }};

您将使用相同的条目两次产生双重结果和结果,例如:

  

[1 = fred,22 = lenny,1 = fred,77 = tommy] [2 = anja,55 = henry,2 = anja,   43 =阿尔弗雷德]

然而,通过一些小的调整可以很容易地解决这些问题。

如果您不熟悉流,lambda或递归,我建议您使用命令式方法实现相同的功能。还要注意我在示例代码中并不关心性能,因为我认为这个问题是一种练习。

答案 1 :(得分:-1)

尝试这样的事情:

@SafeVarargs
private static void check( final List<String> results,
                           final Map.Entry<Integer, String>... vals )
{
    int sum = 0;
    for ( final Map.Entry<Integer, String> val : vals )
    {
        final Integer key = val.getKey();
        sum += null == key ? 0 : key;
    }
    if ( sum < 1000 && 0 == ( sum % 100 ) )
    {
        final StringBuilder result = new StringBuilder( 200 );
        for ( final Map.Entry<Integer, String> val : vals )
        {
            result.append( " + " ).append( val.getKey() );
        }
        results.add( result.append( " = " ).append( sum ).substring( 3 ) );
        for ( final Map.Entry<Integer, String> val : vals )
        {
            results.add( val.getValue() );
        }
    }
}

private static void compare2( final HashMap<Integer, String> values,
                              final List<String> results )
{
    if ( values.size() > 1 )
    {
        for ( final HashMap.Entry<Integer, String> entry1 : values.entrySet() )
        {
            for ( final HashMap.Entry<Integer, String> entry2 : values.entrySet() )
            {
                if ( entry1 == entry2 )
                    continue;
                check( results, entry1, entry2 );
            }
        }
    }
}

private static void compare3( final HashMap<Integer, String> values,
                              final List<String> results )
{
    if ( values.size() > 2 )
    {
        for ( final HashMap.Entry<Integer, String> entry1 : values.entrySet() )
        {
            for ( final HashMap.Entry<Integer, String> entry2 : values.entrySet() )
            {
                for ( final HashMap.Entry<Integer, String> entry3 : values.entrySet() )
                {
                    if ( entry1 == entry2 || entry1 == entry3 || entry2 == entry3 )
                        continue;
                    check( results, entry1, entry2, entry3 );
                }
            }
        }
    }
}