用 Java 中的循环替换代码中的语句

Substitute statements in code with loops in Java

我有这两段代码:

    int prevY = 0;
    // this is the function InsertionSort applied to i
    StdDraw.setPenColor(Color.blue);
    for (int i = 1; i <= N; i++) {
        int x = i;
        int y = runInsertion(i);
        int prevX = i - 1;
        StdDraw.setPenRadius(lineRadius);
        StdDraw.line(prevX, prevY, x, y);
        StdDraw.setPenRadius(pointRadius);
        StdDraw.point(x, y);
        prevY = y;
    }

    prevY = 0;
    // this is the function SelectionSort applied to i
    StdDraw.setPenColor(Color.black);
    for (int i = 1; i <= N; i++) {
        int x = i;
        int y = runSelection(i);
        int prevX = i - 1;
        StdDraw.setPenRadius(lineRadius);
        StdDraw.line(prevX, prevY, x, y);
        StdDraw.setPenRadius(pointRadius);
        StdDraw.point(x, y);
        prevY = y;
    }

除了将使用的颜色和将使用的排序算法稍有变化外,它们都做同样的事情。

有什么方法可以为颜色和排序算法创建一个数组,例如:

String[] algorithms = {"runInsertion", "runSelection"}
String[] colors = {"blue", "black"};

然后用 for 循环调用适当的索引,这样代码就被缩短了。

我知道这不会像我提议的那样起作用,但我只是想知道是否有一种方法或特定方法可以让我这样做。

解决此问题的 'Design pattern' 方法称为模板方法。它涉及为您的算法创建一个抽象 class,它将定义和实现例如方法 step1()step3(),以及一个 抽象 方法step2() 算法的不同实现以不同的方式实现。但是,对于您的目的来说,这似乎有点矫枉过正。通过使用 draw(x, y) 方法来包含这些行来减少一些重复可能是最简单的:

StdDraw.setPenRadius(lineRadius);
StdDraw.line(prevX, prevY, x, y);
StdDraw.setPenRadius(pointRadius);
StdDraw.point(x, y);

只需将您的逻辑提取到具有所需参数的方法中:

void work(Color color, Function<Integer, Integer> algorithm) {
    int prevY = 0;
    StdDraw.setPenColor(color);
    for (int i = 1; i <= N; i++) {
        int x = i;
        int y = algorithm.apply(i);
        int prevX = i - 1;
        StdDraw.setPenRadius(lineRadius);
        StdDraw.line(prevX, prevY, x, y);
        StdDraw.setPenRadius(pointRadius);
        StdDraw.point(x, y);
        prevY = y;
    }
}

并称它为:

work(Color.blue, this::runInsertion);
work(Color.black, this::runSelection);

或数组:

List<Function<Integer, Integer>> algorithms = Arrays.asList(this::runInsertion, this::runSelection);
List<Color> colors = Arrays.asList(Color.blue, Color.black);

for (int i = 0; i < algorithms.size(); i++) {
    work(colors.get(i), algorithms.get(i));
}

是的,一种可能的方法是使用函数对象(不幸的是,它不像输入方法变量名那么容易,因为方法不是第一个 class 对象,因为它们在 Java脚本).

Java 中的函数 class 如下所示:

public class Function<T,V> {   // T is a generic for your input type
    abstract V apply(T input);    // V is a generic for your output type
}

然后就像将代码提取到方法中一样简单,您可以在其中输入颜色字符串和相应的函数对象(对于 Map 来说听起来不错!)以下实现的唯一警告是我'我不太确定 runSelection 和 runInsertion 是如何实现的,但我不认为它们接受一个 int 并输出一个 int。

// Make the map somewhere earlier in the code
Map<String, Function<Integer, Integer> map =  new HashMap();
map.put("blue", new Function<Integer, Integer>(){ 
    Integer apply(Integer input) {
        return runInsertion(input);
    }
}
map.put("black", new Function<Integer, Integer>(){ 
    Integer apply(Integer input) {
        return runSelection(input);
    }
}

for (Entry<String, Function<Integer, Integer>> entry : map.entrySet()) {
    doExtractedMethod(entry.getKey(), entry.getValue());
}

...

public void doExtractedMethod(String color, Function<Integer, Integer> function) {

    int prevY = 0;
    // this is the function InsertionSort applied to i
    StdDraw.setPenColor(color);      // COLOR USED HERE
    for (int i = 1; i <= N; i++) {
        int x = i;
        int y = function.apply(i);   // FUNCTION USED HERE
        int prevX = i - 1;
        StdDraw.setPenRadius(lineRadius);
        StdDraw.line(prevX, prevY, x, y);
        StdDraw.setPenRadius(pointRadius);
        StdDraw.point(x, y);
        prevY = y;
    }
} 

您可以简单地创建一个可以使用参数调用的方法来调用您想要的选项。在 java 8 中,您甚至可以将不同的算法(runInsertion(i)runSelection(i))称为作为 lambda 工作的方法引用。

public void sortWithAlgorithm(Color color, Function<Integer, Integer> algorithm) {
    int prevY = 0;
    StdDraw.setPenColor(color);
    for (int i = 1; i <= N; i++) {
        int x = i;
        int y = algorithm.apply(i);
        int prevX = i - 1;
        StdDraw.setPenRadius(lineRadius);
        StdDraw.line(prevX, prevY, x, y);
        StdDraw.setPenRadius(pointRadius);
        StdDraw.point(x, y);
        prevY = y;
    }
}

然后调用这两个,你可以做几个方便的方法:

void sortInsertion (){
    sortWithAlgorithm(Color.Blue, this::runInsertion);
}

void sortSelection() {
    sortWithAlgorithm(Color.Black, this::runSelection);
}