java 管道设计_使用管道流实现Java 8阶段构建器
Step builder多階段步驟構(gòu)造器模式是一種對(duì)象創(chuàng)建軟件設(shè)計(jì)模式。與傳統(tǒng)構(gòu)建器模式進(jìn)行比較時(shí),步驟構(gòu)建器模式提供了一些簡(jiǎn)潔的好處。Step Builder模式的主要優(yōu)勢(shì)之一是為客戶提供有關(guān)如何使用API??的指南。它可以看作是構(gòu)建器模式和狀態(tài)機(jī)的混合,事實(shí)上,這種模式通常被稱為構(gòu)建對(duì)象的向?qū)А?/p>
優(yōu)點(diǎn)
通過對(duì)象創(chuàng)建過程逐步為API提供用戶指南。
一旦對(duì)象處于一致狀態(tài),API用戶就可以調(diào)用構(gòu)建器的build()方法。
減少了創(chuàng)建不一致對(duì)象實(shí)例的機(jī)會(huì)。
對(duì)必填字段進(jìn)行排序初始化。
流暢的API。
無需為字段驗(yàn)證提供validate()方法。
缺點(diǎn)
實(shí)現(xiàn)模式本身所需的代碼可讀性低。
沒有eclipse插件來幫助代碼生成。(另一方面,Builder模式生成器有很多代碼生成器)。
案例:
由于Step Builder模式是一種創(chuàng)建性設(shè)計(jì)模式,因此我們將重點(diǎn)放在其目的 - 創(chuàng)建對(duì)象上。
API使用示例如下所示:
Email email =
Email.builder().from(EmailAddress.of("Microservices Weekly "))
.to(EmailAddress.of("svlada@gmail.com"))
.subject(Subject.of("Subject"))
.content(Content.of("Test email"))
.build();
這個(gè)API內(nèi)部是如何實(shí)現(xiàn)的?
public class Email {
private EmailAddress from;
private List to;
private List cc;
private List bcc;
private Subject subject;
private Content content;
public static FromStep builder() {
return new Builder();
}
public interface FromStep {
ToStep from(EmailAddress from);
}
public interface ToStep {
SubjectStep to(EmailAddress... from);
}
public interface SubjectStep {
ContentStep subject(Subject subject);
}
public interface ContentStep {
Build content(Content content);
}
public interface Build {
Email build();
Build cc(EmailAddress... cc);
Build bcc(EmailAddress... bcc);
}
public static class Builder implements FromStep, ToStep, SubjectStep, ContentStep, Build {
private EmailAddress from;
private List to;
private List cc;
private List bcc;
private Subject subject;
private Content content;
@Override
public Email build() {
return new Email(this);
}
@Override
public Build cc(EmailAddress... cc) {
Objects.requireNonNull(cc);
this.cc = new ArrayList(Arrays.asList(cc));
return this;
}
@Override
public Build bcc(EmailAddress... bcc) {
Objects.requireNonNull(bcc);
this.bcc = new ArrayList(Arrays.asList(bcc));
return this;
}
@Override
public Build content(Content content) {
Objects.requireNonNull(content);
this.content = content;
return this;
}
@Override
public ContentStep subject(Subject subject) {
Objects.requireNonNull(subject);
this.subject = subject;
return this;
}
@Override
public SubjectStep to(EmailAddress... to) {
Objects.requireNonNull(to);
this.to = new ArrayList(Arrays.asList(to));
return this;
}
@Override
public ToStep from(EmailAddress from) {
Objects.requireNonNull(from);
this.from = from;
return this;
}
}
private Email(Builder builder) {
this.from = builder.from;
this.to = builder.to;
this.cc = builder.cc;
this.bcc = builder.bcc;
this.subject = builder.subject;
this.content = builder.content;
}
public EmailAddress getFrom() {
return from;
}
public List getTo() {
return to;
}
public List getCc() {
return cc;
}
public List getBcc() {
return bcc;
}
public Subject getSubject() {
return subject;
}
public Content getContent() {
return content;
}
}
實(shí)施的經(jīng)驗(yàn)法則:
向您的類添加依賴項(xiàng)。建議將private修飾符添加到類屬性中。
將每個(gè)創(chuàng)建步驟定義為基類中的內(nèi)部接口。
每個(gè)創(chuàng)建步驟都應(yīng)該返回鏈中的下一步(界面)。
最后一步應(yīng)該是名為“Build”的接口,它將提供build()方法。
定義一個(gè)內(nèi)部靜態(tài)Builder類,它實(shí)現(xiàn)所有已定義的步驟。
實(shí)現(xiàn)步驟接口方法。
新案例:
public static class Coffee {
private final CoffeeType type; // Compulsory, one of arabica, robusta, moka...private final Quantity quantity;// Compulsoryprivate final Optional sugar;
private final Optional cream;
}
@FunctionalInterface
interface RequireCoffeeType {
RequireQuantity coffeeType(CoffeeType type);
}
@FunctionalInterface
interface RequireQuantity {
FinalStage quantity(Quantity quantity);
}
public final class FinalStage {
private final CoffeeType type;// Obtained through the staged builderprivate final Quantity quantity;// Obtained through the staged builderprivate Optional sugar;// Regular builder for this optional fieldprivate Optional cream;// Regular builder for this optional field// ....public Coffee build() {
return new Coffee(type, quantity, sugar, cream);
}
}
public static RequireCoffeeType builder() {
return type -> quantity -> new FinalStage(type, quantity);
}
它可以強(qiáng)制調(diào)用者調(diào)用所有階段,最終獲得構(gòu)建方法,并確保不會(huì)忘記強(qiáng)制階段,
遵循這種模式很難:
很難重用上面定義的階段(功能接口)
很難在階段提出替代選擇。
讓我們提出我們想要構(gòu)建的以下事件:
class UserConnected implements Event {
private final User user;
private final MailboxSession.SessionId sessionId;
// Constructor & getters}
class MailboxCreated implements Event {
private final User user;
private final MailboxSession.SessionId sessionId;
private final MailboxId mailboxId;// Constructor & getters}
這是兩個(gè)創(chuàng)建事件,分別是用戶連接上的事件和郵箱已經(jīng)創(chuàng)建的事件。由于我們的事件具有類似的結(jié)構(gòu),我們最終會(huì)得到大量重復(fù)的代碼!
使用當(dāng)前模式定義,分階段構(gòu)建器看起來像這樣,沒有其他選擇,并且階段重用:
public static class UserConnectedBuilder {
@FunctionalInterface
public interface RequireUser {
RequireSessionId user(User user);
}
@FunctionalInterface
public interface RequireSessionId {
FinalStage sessionId(MailboxSession.SessionId sessionId);
}
public static class FinalStage {
private final User user;
private final MailboxSession.SessionId sessionId;
// constructorpublic UserConnected build() {
return new UserConnected(user, sessionId);
}
}
public static RequireUser builder() {
return user -> sessionId -> new FinalStage(user, sessionId);
}
}
public static class MailboxCreatedBuilder {
@FunctionalInterface
public interface RequireUser {
RequireSessionId user(User user);
}
@FunctionalInterface
public interface RequireSessionId {
RequireMailboxId sessionId(MailboxSession.SessionId sessionId);
}
@FunctionalInterface
public interface RequireMailboxId {
FinalStage mailboxId(MailboxId mailboxId);
}
public static class FinalStage {
private final User user;
private final MailboxSession.SessionId sessionId;
private final MailboxId mailboxId;// constructorpublic MailboxCreated build() {
return new MailboxCreated(user, sessionId, mailboxId);
}
}
public static RequireUser builder() {
return user -> sessionId -> mailboxId -> new FinalStage(user, sessionId, mailboxId);
}
}
由于我們的事件具有類似的結(jié)構(gòu),我們最終會(huì)得到大量重復(fù)的代碼!
我們可以看到,作為調(diào)用者,我們還需要明確指定每個(gè)階段:
MailboxCreatedBuilder.builder()
.user(User.fromUsername("bob"))
.sessionId(SessionId.of(45))
.mailboxId(MailboxId.of(15))
.build();
MailboxCreatedBuilder.builder()// .mailboxSession(session) // not allowed.user(session.getUser())
.sessionId(session.getId())
.mailboxId(MailboxId.of(15))
.build();
希望我們可以使用一些Java特異功能來克服這些限制......
具有泛型的獨(dú)立階段
通過使我們的階段成為通用的,我們可以讓調(diào)用者指定下一個(gè)階段(通過構(gòu)建器方法簽名),這將使階段重用和解除彼此之間的階段。
使用默認(rèn)方法的替代(跳過階段)
我們可以定義將兩個(gè)階段組合在一起的“元階段”。然后,“元階段”可以公開一種默認(rèn)方法,允許將兩個(gè)階段分解為單個(gè)階段。
上面的例子現(xiàn)在看起來像這樣:
@FunctionalInterface
public interface RequireUser {
T user(User user);
}
@FunctionalInterface
public interface RequireSessionId {
T sessionId(MailboxSession.SessionId sessionId);
}
@FunctionalInterface // "meta-stage" session combining to stages into onepublic interface RequireSession extends RequireUser> {
default T session(MailboxSession session) {
return user(session.getUser())
.sessionId(session.getId());
}
}
@FunctionalInterface
public interface RequireMailboxId {
T mailboxId(MailboxId mailboxId);
}
public static class UserConnectedBuilder {
public static class FinalStage {
private final User user;
private final MailboxSession.SessionId sessionId;// constructorpublic UserConnected build() {
return new UserConnected(user, sessionId);
}
}
public static RequireSession builder() {
return user -> sessionId -> new FinalStage(user, sessionId);
}
}
public static class MailboxCreatedBuilder {
public static class FinalStage {
private final User user;
private final MailboxSession.SessionId sessionId;
private final MailboxId mailboxId;// constructorpublic MailboxCreated build() {
return new MailboxCreated(user, sessionId, mailboxId);
}
}
public static RequireSession> builder() {
return user -> sessionId -> mailboxId -> new FinalStage(user, sessionId, mailboxId);
}
}
現(xiàn)在,用戶可以獲得所需的便捷方法,更不用說代碼共享了......
MailboxCreatedBuilder.builder()
.user(User.fromUsername("bob"))
.sessionId(SessionId.of(45))
.mailboxId(MailboxId.of(15))
.build();
MailboxCreatedBuilder.builder()
.mailboxSession(session)// now allowed.mailboxId(MailboxId.of(15))
.build();
此外,構(gòu)建器方法類型顯式地向調(diào)用者公開所需的階段,而不是僅暴露下一個(gè)階段......
總結(jié)
以上是生活随笔為你收集整理的java 管道设计_使用管道流实现Java 8阶段构建器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spark mongo java_jav
- 下一篇: java 判断日期周几_Java 输入一