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();
此外,构建器方法类型显式地向调用者公开所需的阶段,而不是仅暴露下一个阶段......