java 管道设计_使用管道流实现Java 8阶段构建器

Step builder多阶段步骤构造器模式是一种对象创建软件设计模式。与传统构建器模式进行比较时,步骤构建器模式提供了一些简洁的好处。Step Builder模式的主要优势之一是为客户提供有关如何使用API​​的指南。它可以看作是构建器模式和状态机的混合,事实上,这种模式通常被称为构建对象的向导。

优点

通过对象创建过程逐步为API提供用户指南。

一旦对象处于一致状态,API用户就可以调用构建器的build()方法。

减少了创建不一致对象实例的机会。

对必填字段进行排序初始化。

流畅的API。

无需为字段验证提供validate()方法。

缺点

实现模式本身所需的代码可读性低。

没有eclipse插件来帮助代码生成。(另一方面,Builder模式生成器有很多代码生成器)。

案例:

由于Step Builder模式是一种创建性设计模式,因此我们将重点放在其目的 - 创建对象上。

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();

这个API内部是如何实现的?

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;

}

}

实施的经验法则:

向您的类添加依赖项。建议将private修饰符添加到类属性中。

将每个创建步骤定义为基类中的内部接口。

每个创建步骤都应该返回链中的下一步(界面)。

最后一步应该是名为“Build”的接口,它将提供build()方法。

定义一个内部静态Builder类,它实现所有已定义的步骤。

实现步骤接口方法。

新案例:

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);

}

它可以强制调用者调用所有阶段,最终获得构建方法,并确保不会忘记强制阶段,

遵循这种模式很难:

很难重用上面定义的阶段(功能接口)

很难在阶段提出替代选择。

让我们提出我们想要构建的以下事件:

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}

这是两个创建事件,分别是用户连接上的事件和邮箱已经创建的事件。由于我们的事件具有类似的结构,我们最终会得到大量重复的代码!

使用当前模式定义,分阶段构建器看起来像这样,没有其他选择,并且阶段重用:

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);

}

}

由于我们的事件具有类似的结构,我们最终会得到大量重复的代码!

我们可以看到,作为调用者,我们还需要明确指定每个阶段:

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特异功能来克服这些限制......

具有泛型的独立阶段

通过使我们的阶段成为通用的,我们可以让调用者指定下一个阶段(通过构建器方法签名),这将使阶段重用和解除彼此之间的阶段。

使用默认方法的替代(跳过阶段)

我们可以定义将两个阶段组合在一起的“元阶段”。然后,“元阶段”可以公开一种默认方法,允许将两个阶段分解为单个阶段。

上面的例子现在看起来像这样:

@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);

}

}

现在,用户可以获得所需的便捷方法,更不用说代码共享了......

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();

此外,构建器方法类型显式地向调用者公开所需的阶段,而不是仅暴露下一个阶段......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值