考慮下面的類: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內部),但是這將允許構建器構建部分構建的對象,這是否違背構建器模式? –