重构覆盖方法,这些方法仅在正文中间有差异

时间:2017-03-25 06:19:49

标签: java refactoring dry

有时候,方法在他们身体的中间位置有唯一的区别,很难将它们概括为一般,或者将代码的常用部分提取到单个方法中。

问题本身:您如何重构以下接口方法的实现,以避免for循环体周围的重复代码?

interface MyInterface {
    Integer myInterfaceMethod(String inputStr);
    Integer myInterfaceOtherMethod(String inputStr)
}

class MyClass implements MyInterface {
    public Integer myInterfaceMethod(String inputStr) {
        @Override
        try {
            List<String> listDependingOnString = getListByString(inputStr);
            Integer result = -1;
            if (inputStr != null) {
                result = 0;
                for (String str : listDependingOnString) {

                    // Some different code, given just for example
                    result += str.length();

                }
            }

            return result;
        } catch (Exception e) {
            exceptionProcessing(e);

            return null;
        }
    }

    @Override
    public Integer myInterfaceOtherMethod(String inputStr) {
        try {
            List<String> listDependingOnString = getListByString(inputStr);
            Integer result = -1;
            if (inputStr != null) {
                result = 0;
                for (String str : listDependingOnString) {

                    // Some different code, given just for example
                    System.out.println(str);
                    ++result;

                }
            }

            return result;
        } catch (Exception e) {
            exceptionProcessing(e);

            return null;
        }
    }
}

2 个答案:

答案 0 :(得分:2)

对于这个特殊的例子,lambda可以很好地工作:

private Integer computeStringFunction(String inputStr, BiFunction<Integer,String,Integer> accumulator) {
    try {
        List<String> listDependingOnString = getListByString(inputStr);
        Integer result = -1;
        if (inputStr != null) {
            result = 0;
            for (String str : listDependingOnString) {
                result = accumulator.apply(result, str);
            }
        }

        return result;
    } catch (Exception e) {
        exceptionProcessing(e);

        return null;
    }

public Integer myInterfaceMethod(String inputStr) {
    return computeStringFunction(inputStr,
        (Integer oldValue, String str) -> oldValue + str.length());
}

public Integer myInterfaceOtherMethod(String inputStr) {
    return computeStringFunction(inputStr,
        (Integer oldValue, String str) -> {
             System.out.println(str);
             return oldValue + 1;
        });
}

&#34;累加器&#34;这是一个函数,它接受一个整数和一个字符串,并返回另一个整数,其目的是保持&#34;运行总数&#34;某种。

BiFunction documentation

注意:未经过测试

答案 1 :(得分:2)

在代码中删除duplicate pattern的关键是将公共部分抽象到一个地方然后找到一种方法来传递"code pieces"的不同部分作为执行的参数,对于其中函数是一等公民(JavaScript,Python),你总是可以将"code pieces"包装为函数。但它不适用于Java,因为Java中的方法不是值,解决它的一种方法是定义interface,然后传递实现interface的类的实例。作为参数,lambda expression中的Java 8可以更简单。

以相关代码为例,common pattern为:

  • 迭代列表并处理每个项目
  • 累积每个项目的结果并返回

然后我们可以定义两个接口:

@FunctionalInterface
public interface ItemHandler<T, R> {
    /**
     * Takes input item of type T, then returns result of type R
     */
    R handle(T t);
}

另一个interface来积累结果:

@FunctionalInterface
public interface ItemResultAccumulator<T> {
    T accumulate(T t1, T t2);
}

然后您的代码可以重构为(我删除了所有异常处理和null检查代码,以使代码更简洁,无法查看):

public class MyClass implements MyInterface {
    private static final ItemResultAccumulator<Integer> ADDER = (t1, t2) -> t1 + t2;

    @Override
    public Integer myInterfaceMethod(String inputStr) {
        return processList(getListByString(inputStr), s -> s.length(), ADDER); 
    }

    @Override
    public Integer myInterfaceOtherMethod(String inputStr) {
        return processList(getListByString(inputStr), s -> {
            System.out.println(s);
            return Integer.valueOf(1);
        }, ADDER);
    }

    private Integer processList(List<String> list, ItemHandler<String, Integer> handler, ItemResultAccumulator<Integer> accumulator) {
        Integer result = 0;
        if (list != null && list.size() > 0) {
            for (String item : list) {
                result = accumulator.accumulate(result, handler.handle(item));
            }
        }

        return result;
    }

    private List<String> getListByString(String inputStr) {
        // Your logic to generate list by input
        return Lists.newArrayList(inputStr.split(","));
    }
}

这是我对这个问题的一点思考,希望这可能会有所帮助: - )