【发布时间】:2017-03-09 00:03:56
【问题描述】:
考虑以下类:
@Getter
public class EmailVO {
private final Long id;
private final String firstName;
private final String email;
private final String address;
@Slf4j
@Component
@Scope("prototype")
public static class Builder {
private Lead lead;
private Long id;
private String firstName;
private String email;
private String address;
public Builder fromLead(Lead lead) {
this.lead = lead;
return this;
}
public EmailVO build() {
if (lead == null) {
log.error("Failed to build EmailVO: lead was not initialized");
return new EmailVO(this);
}
User user = lead.getUser();
id = user.getId();
firstName = user.getFirstName();
email = user.getEmail();
address = user.getAddress();
return new EmailVO(this);
}
}
private EmailVO(Builder builder) {
id = builder.id;
firstName = builder.firstName;
email = builder.email;
address = builder.address;
if (id == null ||
firstName == null ||
email == null ||
address == null)
{
throw new IllegalStateException(); // Maybe some ohter Unchecked Exception would be better
}
}
}
据我所知,这将是一个适当的 VO 类实现,它只允许从它的构建器构建新实例,它也充分遵循构建器模式(如果我错了,请纠正我)。
从 SOLID 的角度来看,此代码很好,因为构建器的单一职责是聚合数据以构建 EmailVO,它的构造器将负责只让其有效实例变为现实。
现在,如果您关心代码的混乱和可读性(想象一个更大的 VO),构建器可能会在没有初始化所需参数的情况下尝试构建,而不是让对象的构造器失败,这可能会删除许多构造函数内部的空检查。在示例代码中,如果lead 字段为null,则此验证可能会引发异常,而不是让EmailVO 的构造函数检查完整性,尽管这是构造函数的责任。
是否可以从 EmailVO 的构造函数中删除验证并让构建器处理它? 考虑在这种情况下构造函数是 private 使其不可见这个类的外面。
这似乎与 SOLID 背道而驰,尽管如果构建器未验证所需参数,它可能会失败,因为它的一项职责是聚合所需数据以构建 EmailVO 实例。
然而,我想到的一个想法是有一个标志作为EmailVO.Builder 类的成员字段,以表明它是否成功聚合所需的参数,然后EmailVO 的构造函数只能检查(并信任) 这个标志。
【问题讨论】:
-
考虑到您的
EmailVO严格用于保存变量,我会说它应该具有零逻辑。 -
在您的 EmailVO 构造函数中,考虑将
x = builder.x; if (x == null) {}替换为x = Objects.requireNonNull(builder.x); -
@ChristopherSchneider 好点。 VO 对象应该仅用于携带值,而不是用于验证它们,但是让构建器执行此类验证不是违反 SOLID 吗?有人可能会说,您可以更不用说所有需要的验证都发生在一个孤立的方法中(在 Controller 等内部),但这将允许构建器构建部分构造的对象,这是否违反构建器模式?
标签: java solid-principles builder-pattern