首页 > 解决方案 > 结合具有不同参数或不同参数编号的消费者

问题描述

比方说,我们的方法接收输入String 并返回一些 List output。这个输出是一些生成器的结果,其中一些依赖于输入,而一些不依赖于输入——它们只是添加预定义的值。我想像一些函数接口(例如消费者)的列表一样实现这些生成器,然后将它们组合成一个消费者并将其应用于输入字符串。

因此,我将能够轻松独立地更换小型发电机。但问题是,并不是我所有的生成器都需要输入字符串作为参数,我只是将这个参数传递给那里,原因只有一个——能够将这些消费者与其他消费者结合起来。

public class ConsumersTest {

private static <T, U> BiConsumer<T, U> combine(List<BiConsumer<T, U>> consumers) {
    return consumers.stream().reduce((arg1, arg2) -> {}, BiConsumer::andThen);
}

List<String> generate(String input) {
    ArrayList<String> output = new ArrayList<>();
    combine(getGenerators()).accept(input, output);
    return output;
}

private List<BiConsumer<String, List<String>>> getGenerators() {
    return Arrays.asList(
            this::addFirstDependent,
            this::addSecondIndependent
    );
}

private void addFirstDependent(String input, List<String> output) {
    if (input.contains("some string")) {
        output.add("First-Dependent");
    }
}

private void addSecondIndependent(String input, List<String> output) {
    output.add("Predefined Output");
}}

是否可以将不同的消费者组合在一个保护伞下,并将它们应用到一个地方?或者这是一个坏主意,而不是做这些事情的正确方法?

标签: javalambdajava-8method-referencefunctional-interface

解决方案


在模块化软件和适配器中具有通用接口以使特定实现适合,这并不是一种不寻常的模式。例如

public class ConsumersTest {

    List<String> generate(String input) {
        ArrayList<String> output = new ArrayList<>();
        generators.accept(input, output);
        return output;
    }

    private static <T, U> BiConsumer<T, U> ignoreFirstArg(Consumer<U> consumer) {
        return (t, u) -> consumer.accept(u);
    }

    private final BiConsumer<String, List<String>> generators =
        Stream.<BiConsumer<String, List<String>>>of(
                this::addFirstDependent,
                ignoreFirstArg(this::addSecondIndependent)
        ).reduce(BiConsumer::andThen).orElse((arg1, arg2) -> {});

    private void addFirstDependent(String input, List<String> output) {
        if (input.contains("some string")) {
            output.add("First-Dependent");
        }
    }

    private void addSecondIndependent(List<String> output) {
        output.add("Predefined Output");
    }
}

ignoreFirstArg没有第一个参数的方法的通用适配器也是如此。可以有任意数量的适配器方法。但请注意,如果适配器非常具体,因此只使用一次,也可以在组合代码中编写 lambda 表达式而不是方法引用。请注意,我更改了该代码,以免每次generate(String input)调用都重复评估,否则,当您不重用组合函数时,将它们组合起来毫无意义,因为您也可以使用

List<String> generate(String input) {
    ArrayList<String> output = new ArrayList<>();
    Stream.<BiConsumer<String, List<String>>>of(
            this::addFirstDependent,
            ignoreFirstArg(this::addSecondIndependent)
    ).forEach(g -> g.accept(input, output));
    return output;
}

甚至更简单

List<String> generate(String input) {
    ArrayList<String> output = new ArrayList<>();

    this.addFirstDependent(input, output);
    this.addSecondIndependent(output);

    return output;
}

这并不比功能代码更难维护,因为每个生成器都由一行组成。


推荐阅读