Mit der Einführung von Lambda-Ausdrücken und der Stream-API in Java8 hat die Java-Sprache endlich das Paradigma der funktionalen Programmierung gebracht. Infolgedessen ändern sich auch die Designstandards. Informationen zu Stream-API- und Lambda-Ausdrücken finden Sie in dem guten Buch "Functional Programming with Java", das von O'Reilly veröffentlicht wurde. In Kapitel 4 "Entwerfen mit Lambda" in diesem Buch werden neue Designideen vorgestellt, die Lambda verwenden. In diesem Artikel untersucht und erwägt der Autor, inspiriert von den oben genannten Büchern, neue Möglichkeiten zur Implementierung von Entwurfsmustern mithilfe von Lambda-Ausdrücken und Streams.
Betrachten Sie das Builder-Muster, eines der Muster für die GoF-Generierung. Informationen zur Implementierung des Builder-Musters in Java finden Sie unter diese Seite.
Die folgenden Techniken werden in "Funktionale Programmierung mit Java" vorgestellt.
FluentBuilder
public class MailBuilder {
private String fromAddress = "";
private String toAddress = "";
private List<String> ccAddresses = new ArrayList<>();
private String subject = "";
private String body = "";
private MailBuilder() {
}
public MailBuilder from(String address) {
this.fromAddress = address;
return this;
}
public MailBuilder to(String address) {
this.toAddress = address;
return this;
}
public MailBuilder cc(String address) {
this.ccAddresses.add(address);
return this;
}
public MailBuilder subject(String subject) {
this.subject = subject;
return this;
}
public MailBuilder body(String body) {
this.body = body;
return this;
}
private void doSend() {
StringBuilder sb = new StringBuilder();
sb.append("TO:").append(toAddress).append("\r\n");
if (!ccAddresses.isEmpty()) {
sb.append("CC:").append(String.join(",", ccAddresses)).append("\r\n");
}
sb.append("FROM:").append(fromAddress).append("\r\n");
sb.append("SUBJECT:").append(subject).append("\r\n");
sb.append("BODY:").append(body).append("\r\n");
System.out.println(sb.toString());
}
public static void send(final Consumer<MailBuilder> consumer) {
final MailBuilder mailer = new MailBuilder();
consumer.accept(mailer);
mailer.doSend();
}
Das Verwendungsbeispiel von "Builder" oben ist wie folgt.
FluentBuilder-Usage
MailBuilder.send(mailer -> {
mailer.from("[email protected]")
.to("[email protected]")
.subject("Greeting")
.body("Hello, Mr. President!");
});
Die Vorteile gegenüber dem herkömmlichen Builder, der mit der "fließenden Schnittstelle" zusammengebaut wird, sind folgende.
――Da das Schlüsselwort "new" nicht verwendet wird, ist es lesbarer und fließender.
Eine der Unannehmlichkeiten bei der Verwendung eines Builders vom Typ "fließende Schnittstelle" besteht darin, dass Sie Methodenaufrufe abhängig von den Bedingungen wechseln oder Methoden wiederholt aufrufen möchten. Aufgrund der Java-Sprachspezifikationen ist es nicht möglich, die Steuerungssyntax in eine durch Punkte "." Verbundene Methodenkette einzubetten. Daher wird die Methodenkette in die Mitte unterteilt und mithilfe von if- und for-Anweisungen gesteuert Ich bin nicht mehr fließend. Können Sie dieses Problem nicht gut lösen?
Fügen Sie eine Methode hinzu, die "Consumer
MoreFluentBuilder
public MailBuilder doIf(boolean condition, final Consumer<MailBuilder> consumer) {
if (condition) {
consumer.accept(this);
}
return this;
}
Obwohl der Lambda-Ausdruck verschachtelt wäre, konnten wir die bedingte Kontrolle integrieren, ohne die Methodenkette zu unterbrechen.
MoreluentBuilder-Usage
MailBuilder.send(mailer -> {
mailer.from("[email protected]")
.to("[email protected]")
.doIf(someCondition(), m -> m.cc("[email protected]"))
.subject("Greeting")
.body("Hello, Mr. President!");
});
Diesmal ist es etwas kompliziert, da wir zwei Funktionstypen als Argumente verwenden müssen.
Zunächst empfängt es das Objekt, das im Typ "Iterable
MoreFluentBuilder2
public <T> MailBuilder foreach(Iterable<T> iterable, final BiConsumer<MailBuilder, T> consumer) {
iterable.forEach(t -> consumer.accept(this, t));
return this;
}
Ich konnte iterative Steuerelemente einbetten, ohne die Methodenkette zu unterbrechen, wie unten gezeigt.
MoreFluentBuilder2-Usage
final List<String> ccAddresses = Arrays.asList("[email protected]", "[email protected]");
MailBuilder.send(mailer -> {
mailer.from("[email protected]")
.to("[email protected]")
.foreach(ccAddresses, (m, ccAddress) -> m.cc(ccAddress))
.subject("Greeting")
.body("Hello, Mr. President!");
});
Wenn Sie Lambda-Ausdrücke gut nutzen, können Sie Code schreiben, der sauberer und klarer ist. Dieses Mal habe ich untersucht, wie die Implementierung des Builder-Musters vom Typ "Fluent Interface" fließender gestaltet werden kann.