DDDの原則によると、一貫したオブジェクトを作成し、オブジェクトが正しい状態であることを確認するために、ファクトリーメソッドを使用しています。
今、私はセッターメソッドの内部ロジックについて疑問があります。次のコードスニペットに似たオブジェクトに縛られているので、例として取り上げましょう。
_public class UserCredentials {
private String username;
private UserCredentials() {
super();
}
public static UserCredentials create (final String username) {
String username = username.toUpperCase();
UserCredentials newInstance = new UserCredentials(username);
return newInstance;
}
private UserCredentials(final String username) {
this.username = username;
}
public String getUsername() {
return this.username;
}
public void setUsername(final String username) {
this.username = username;
}
public void checkConsitency() {
...
isUppercase();
...
}
}
_
不変条件があります。資格情報のユーザー名は常に大文字である必要があります。ここで、ユーザー名を変更しても不変条件に違反しないことを確認したいと思います。
しかし、どうすればルールを保証できますか?
セッターメソッドを書き直して、変換ロジックをセッターに追加します。欠点:セッターにはロジックが含まれています。
私はクライアントに依存しています。クライアントは常に大文字のユーザー名を提供し、違反した場合は整合性の例外をスローします。欠点:間違った使用法の原因を見つけるのは困難であり、さらにその悪い習慣はまったくありません。
Setterメソッドを削除し、変換ロジックを含むchangeUsername(String username)
のようなドメインメソッドに置き換えます。欠点:外部の開発者は、setterメソッドを見逃す可能性があります。
「資格情報のユーザー名は常に大文字でなければならない」という文言のため、私は代替案3を好む傾向があります。
しかし、よりスマートなソリューションはありますか?
ソリューション#1を選択します。検証または強制ロジックを含むセッターには何の問題もありません。実際、パブリックメンバーフィールドの代わりにセッターとゲッターを使用する唯一の理由です!
代わりにコンストラクターを使用しない理由がないため、create
ファクトリメソッドも少し厄介です。
public class UserCredentials {
private String username;
public UserCredentials(final String username) {
super();
this.username = coerceUsername(username);
}
public String getUsername() {
return this.username;
}
public void setUsername(final String username) {
this.username = coerceUsername(username);
}
private static String coerceUsername(final String username) {
return username.toUpperCase();
}
}