Java 类似于 IntStream 的静态构建

Java static build similar to IntStream

我的目标是提供一个 class 来构建一个函数链来执行一些任务。这是我到目前为止能想到的

函数class

public class Loop {
    private final int from;
    private final int to;

    private Loop(int from, int to) {
        this.from = from;
        this.to = to;
    }

    public static Loop from(int from) {
        return new Loop(from, 0);
    }

    public static Loop to(int to) {
        return new Loop(0, to);
    }

    public void execute(Executable executable) {
        for (int i = from; i < to; i++) {
            executable.execute();
        }
    }
}

可执行界面

@FunctionalInterface
public interface Executable {
    void execute();
}

它可以对一个参数(从或到)起作用,例如

Loop.to(10).execute(() -> {});

但我希望它适用于多个参数,例如

Loop.from(5).to(10).execute(() -> {});

我怎样才能做到这一点?此外,我不确定 static from 和 static to 方法是否适合 Loop class 以及一个冗余参数。

如果 from 和 non-static 的静态变体具有相同的名称,那将是理想的选择,但这不受支持。参数或名称必须不同。

因此,我将创建私有构造函数 public 并添加第二个 no-args 构造函数,以便调用可以变为:

new Loop().from(5).to(10).execute(...)
new Loop(5, 10).execute(...)

要使其正常工作,fromto 必须不再是静态的。然后你必须决定这些方法是否改变了它们被调用的 Loop 实例,或者它们是否 return 一个新对象:

public Loop from(int from) {
    return new Loop(from, to);
}

public Loop to(int to) {
    return new Loop(from, to);
}

public Loop from(int from) {
    this.from = from; // no longer final
    return this;
}

public Loop to(int to) {
    this.to = to; // no longer final
    return this;
}

如果您想更进一步,您可以将 class 重命名为 LoopBuilder 并创建一个 build() 方法,该方法 return 是一个 Loop 具有字段和以前一样,但没有 fromto 方法,只有 execute 方法:

public static class Loop {

    private final int from;
    private final int to;

    public Loop(int from, int to) {
        this.from = from;
        this.to = to;
    }

    public void execute(Executable executable) {
        for (int i = from; i < to; i++) {
            executable.execute();
        }
    }
    
    public static LoopBuilder builder() {
        return new LoopBuilder();
    }
}

public static class LoopBuilder {
    private int from;
    private int to;

    public LoopBuilder from(int from) {
        this.from = from;
        return this;
    }

    public LoopBuilder to(int to) {
        this.to = to;
        return this;
    }

    public Loop build() {
        return new Loop(from, to);
    }
}

调用将变成

Loop.builder().from(5).to(10).build().execute(...);

可以采用多种方法。解决方案越复杂,它们通常就越复杂。让我们从一个简单的解决方案开始。

public class Loop {
    private final int from;
    private final int to;

    private Loop(Builder builder) {
        this.from = builder.from();
        this.to = builder.to();
    }

    public static Builder from(int from) {
        return new Builder().from(from);
    }

    public static Builder to(int to) {
        return new Builder().to(to);
    }

    public void execute(Runnable executable) {
        for (int i = from; i < to; i++) {
            executable.run();
        }
    }

    public static class Builder {
        private int from = 0;
        private Integer to = null;

        private Builder() {}

        public Builder from(int from) {
            this.from = from;
            return this;
        }

        private int from() {
            return from;
        }

        public Builder to(int to) {
            this.to = to;
            return this;
        }

        private int to() {
            return to;
        }

        public void execute(Runnable runnable) {
            Objects.requireNonNull(runnable);
            new Loop(this).execute(runnable);
        }
    }
}

Ideone demo

这已经很了不起了。但是我们可以,例如,多次调用 from(...)to(...)。如果我们只允许调用 from(...) 一次,之后只允许调用 to(...),那么我们需要定义更多类型。我们可以通过添加接口 LoopFromSetBuilderLoopToSetBuilderLoopAllSetBuilder:

来实现这一点
interface LoopFromSetBuilder {
    LoopAllSetBuilder to(int to);
}

interface LoopToSetBuilder {
    LoopAllSetBuilder from(int from);
}

interface LoopAllSetBuilder {
    void execute(Runnable runnable);
}

加上方法上的一些小调整 Loop

class Loop {
    ...
    public static LoopFromSetBuilder from(int from) {
        return new Builder().from(from);
    }

    public static LoopToSetBuilder to(int to) {
        return new Builder().to(to);
    }
    ...
}

并让 Builder 实现这些接口:

    public static class Builder implements LoopFromSetBuilder, LoopToSetBuilder, LoopAllSetBuilder {
        ...
    }

Ideone demo

我们消除了用户多次调用 from(...)to(...) 的可能性。

我没有进一步构建那些“复杂”的流利 API 的经验,但我想构建这样一个 API 的过程会非常痛苦。对于小例子,就像这里一样,我们可能能够拒绝多次设置相同的变量,但是使用更多参数似乎很混乱(可能的状态 - 因此 - 接口似乎是 2^n 的顺序,其中 n 是字段数...所以是的。

如果有人赞成我的答案,也应该考虑赞成 ,因为我的答案的第一个解决方案与 Luk2302 的解决方案非常相似,而且 Luk2302 的答案发布时间比我的早一点。