如何为传递给方法的流畅 lambda 定义顺序

How to define an order for a fluent lambda passed to a method

this talk by venkat subramaniam 中,他制作了以下 Mailer 示例:

class Mailer {
  public Mailer from(String addr) { System.out.println("from"); return this; }
  public Mailer to(String addr) { System.out.println("to"); return this; }
  public Mailer subject(String subjectLine) { System.out.println("subject"); return this; }
  public Mailer body(String message) { System.out.println("body"); return this; }
  public static void send(Consumer<Mailer> block) { 
    Mailer mailer = new Mailer();
    block.accept(mailer);
    System.out.println("sending..."); 
  }
}

public class Sample {
  public static void main(String[] args) {
    Mailer.send(mailer -> {
      mailer.from("builder@agiledeveloper.com")
            .to("venkats@agiledeveloper.com")
            .subject("Your code sucks")
            .body("...");      
    });
  }
}

对于这种特定情况,我知道实施细节可能没有意义,因为像这样的邮寄者不会关心订单,但如果我想强制执行您调用 from 的订单,tosubjectbody 这样你必须从 from 开始,然后是 to,然后是 subject 然后是 body 怎么会我做这个?

我确实在 中看到了答案,但这依赖于使用 newBuilder 方法启动流程,我不确定如何将此模式应用于 lambda 示例。

尽管链接问题中的方法似乎不太适用于此,但可以对其进行一些调整以适合您的目的。

让我们首先添加链接问题中显示的类型:

interface IFromBuilder {
    IToBuilder from(String from);
}

interface IToBuilder {
    ISubjectBuilder to(String to);
}

interface ISubjectBuilder {
    IBodyBuilder subject(String line);
}

interface IBodyBuilder {
    void body(String body);
}

class Mailer implements IFromBuilder, IToBuilder, ISubjectBuilder, IBodyBuilder {

    // implementations...
}

您使用的是接受 Consumer<Mailer>send 方法,而不是 newBuilder 方法。取而代之的是,使用 Consumer<IFromBuilder>

public static void send(Consumer<IFromBuilder> block) { 
    Mailer mailer = new Mailer();
    block.accept(mailer);
    System.out.println("sending..."); 
}

如果你想强制开发人员每次都编写整个方法链,你可以这样做:

将方法链中的最后一个 return 改成另一种类型:

interface ICompletedMailer { // Mailer should also implement this

}

interface IBodyBuilder {
    ICompletedMailer body(String body);
}

并将 Consumer<IFromBuilder> 更改为 Function<IFromBuilder, ICompletedMailer>:

public static void send(Function<IFromBuilder, ICompletedMailer> block) { 
    Mailer mailer = new Mailer();
    block.apply(mailer);
    System.out.println("sending..."); 
}