考虑下面的类:Builder模式和failling
@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){}'with'x = Objects.requireNonNull(builder.x);' – toongeorges
@ChristopherSchneider好点。 VO对象应该仅用于传递值,而不是用于验证它们,但是如果让构建者执行此类验证,它不会违反SOLID吗?人们可以说,你可以让所有需要的验证发生在一个孤立的方法中(在Controller内部),但是这将允许构建器构建部分构建的对象,这是否违背构建器模式? –