【问题标题】:Functional class level arguments in Java 8Java 8 中的函数类级别参数
【发布时间】:2019-04-14 02:48:49
【问题描述】:

我想更加努力地使用 Java 8 的功能特性,并将我的想法转向该范式;但是,我不太确定如何协调这种情况。

例如我最近写了类似这样的东西:

public class ExampleClass {

    private ExampleData exampleData;
    private Function<ExampleData, Boolean> workFunction;

    public ExampleData getExampeData() {
        return exampleData;
    }

    public void setExampleData(ExampleData exampleData) {
        this.exampleData = exampleData;
    }

    public Function<ExampleData, Boolean> getWorkFunction() {
        return workFunction;
    }

    public void setWorkFunction(Function<ExampleData, Boolean> workFunction) {
        this.workFunction = workFunction;
    }
}

然后我继续这样使用它......

public class Worker implements Callable {

    private final ExampleClass exampleClass;

    // ExampleClass serves as a container for the function and it's
    // input data in order to minimize the number of arguments
    // passed to this constructor. Otherwise would be
    // public Worker(ExampleData exampleData, Function<T, R> workFunction, ...) {
    // Note: using "..." here to represent more args.
    public Worker(ExampleClass exampleClass, ...) {
        this.exampleClass = exampleClass;
        ...
    }

    @Override
    public void call() {
        final Boolean isComplete = exampleClass.getWorkFunction().apply(exampleClass.getExampleData());
        if (isComplete) {
            ...
        }
        ...
    }
}

与我认为更传统的方法相比,上述方法是否更受欢迎?

public class ExampleClass {

    private ExampleData exampleData;

    public ExampleClass(ExampleData exampleData) {
        this.exampleData = exampleData;
    }

    public Boolean work() {
          return isComplete(exampleData);
    }
}

以及实现类...

public class Worker implements Callable {

    private ExampleClass exampleClass;

    public Worker(ExampleClass exampleClass, ...) {
        this.exampleClass = exampleClass;
        ...
    }

    @Override
    public void call() {
        final Boolean isComplete = exampleClass.work();
        if (isComplete) {
            ...
        }
        ...
    }
}

如果我完全偏离了基础,使用 Java 8 的适当功能解决方案是什么?

更新:假设我的示例没有返回布尔值。在使用 Java 8 进行函数式编程的上下文中,将函数作为类级参数显式传递更好,还是仅使用传统的面向对象方式传递另一个执行该函数的类更好?

【问题讨论】:

  • 欢迎来到 Stack Overflow!请拨打tour 并访问我们的help center,了解适合本网站的问题类型。诸如此类的基于意见的问题是题外话,因为它们往往会在这里引发愤怒的辩论。如果您可以edit您的问题符合本网站的要求,请这样做。
  • 这几乎不是一个基于意见的问题。根据这个定义,所有设计模式问题都是见仁见智的问题。
  • 关于什么是“基于意见”有不同的意见;-) 您的代码的主要问题是恕我直言,它太模糊和粗略。 ExampleClass 可能有助于了解一个想法,但在这里,情况并非如此:不清楚这个类应该是什么(即它如何映射到“现实世界类”),以及什么Function 部分应该完成。就目前而言,它看起来非常可疑(好像你随机输入了Function,因为......功能!!!111),但也许这背后有更深层次的意义/意图/目标......?!
  • 更具体地说:ExampleClass 基本上是一个 POJO,由两个元素组成:数据和函数。而使用这个类的唯一方式是获取数据和函数,然后用它们做一些事情。除了作为“容器”之外,该类本身似乎没有任何用途。也许一个更现实的例子可以让问题更清楚。
  • ExampleClass 是一个 POJO。它的唯一目的是最小化传递给 Worker 类的参数数量。我想我的问题与 ExampleClass 没有太大关系,它更多地是关于将函数作为类级别参数显式传递,而不是传递执行函数的类。我已经更新了我的问题,希望能澄清这一点。

标签: java design-patterns java-8 functional-programming


【解决方案1】:

函数式编程的要点是函数必须被视为一个对象。

但你知道,函数(方法)在 java 中不是对象。它与 javascript 不同。

所以,我们应该使用名为 Predicate 的接口。

List<Apple> apples = new ArrayList<>();

你想减肥。原来,

List<Apple> weightApples = new ArrayList<>();
for(int i = 0; 9< apples.size(); i++){
    if(apples.getWeight() > 10){
        weightApples.add(apples.get(i));
    }
}

这段代码。

在函数式编程中,函数是“纯函数”。

在纯函数中,应避免在函数中使用外部变量。

而且,我们不关心“使用函数的行”中函数的逻辑

首先,我们需要谓词接口。

interface Predicate<T>{
    public boolean pass(T t);
}

通过泛型,我们可以扩展对象类型。

我们可以做过滤器。

public static <T> List<T> filter(List<T> list, Predicate<T> predicate){
    List<T> result = new ArrayList<>();
    for(T el : list){
        if(predicate.pass(el)){
            result.add(el);
        }
    }

    return result;
}

pass() 还没有实现。

可以通过匿名类实现。

最后,使用 lamda 将方法视为对象!

filter(apples, (Apple apple) -> apple.getWeight()>10);

我不是英语人,所以英语很差。

但我希望它对你有帮助!谢谢。

【讨论】:

  • 这确实有帮助,但是假设我修改了我的示例,以便我想要传递的函数没有返回布尔值,因此不能用作谓词,我试图将函数传递给一个从 Callable 或 Runnable 扩展的工作线程,这意味着该函数必须通过构造函数才能在其可覆盖的 run 方法中使用。拥有一个包含函数的容器类可以吗?
  • 关于这个的问题。避免外部变量是否意味着避免通过构造函数传入的类级别变量?如果是这样,这是否意味着每个类都应该是静态的,才能以纯函数方式实际使用 java?
  • 不是。这是关于功能(方法)的问题。那么,函数应该避免被外部变量应用。必须故意使用静态变量。
【解决方案2】:

首先,一个接受一个参数并返回一个布尔值的函数应该实现Java 8 Predicate

但是,在我看来,谓词并不是要替换任何和所有if 语句。它们旨在用作 Java 8 集合流中的过滤器。您提供的示例似乎不适合这种情况。

【讨论】:

    猜你喜欢
    • 2019-04-08
    • 1970-01-01
    • 2019-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多