作り方
まとめ中です。
import java.util.Objects;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public final class Color {
@NonNull private final String color;
public static Color of(String color) {
return new Color(color);
}
private Color(String color) {
String checked = Objects.requireNonNull(color, "colorがnullです。");
// TODO: 引数の中身のチェックを追加
this.color = checked;
}
@NonNull
public String value() {
return this.color;
}
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
/**
* このオブジェクトの簡潔な説明を返します。
* ただし、この表現は明記せず、変更されることがあります。
*/
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
ポイント
- 値ベース・クラスも参考になりそうです。
- クラスは
final
にする。- これに限らず、原則は
final
がよいです。
- これに限らず、原則は
- ファクトリーメソッド
of
を定義- ファクトリーメソッドを使うため、Flyweightパターンが適用可能。
- サブクラスを返すことも可能だが、
final
なのでサブクラスは存在しない。- Immutablesを使えば、実装とインタフェースを分離可能。
of
は短くて広く使われているため。- 引数の内容に条件がある場合は
ofBase64(String)
のように条件をメソッド名に付ける。 - フォームから渡されたときなど、エラー時にチェック例外を投げたい場合は、別メソッドを作る。
- メソッド名は
parse
が良さそう1。
- メソッド名は
- コンストラクタ or ファクトリで引数のチェックを行う。
- nullチェック
- 空文字列など、使う側からしたらありえないもの
- IllegalArgumentExceptionを投げる2
of
とparse
両方実装する場合を考えると、引数チェックはファクトリの方がいいかもしれない。
- 必要な処理はコンストラクタで全て行っておく。
- 逆に言えば、他のメソッドでIllegalStateExceptionを投げてはいけない。
- 本当の原因であるコンストラクタがどこで呼び出されたかが分からないため、障害解析が困難になる。
toString()
はApache Commons Langを使ってます。toString()
はログに使うことがメインなので、このような実装を好んでいます。- ただし、ValueObjectはオブジェクトのIDには意味がないため、SHORT_PREFIX_STYLEを使います。
- フィールドの値を返したい場合は、他のメソッドを別途定義します。
- 処理から除外したい場合はアノテーション
ToStringExclude
を付けると良いみたいです。 - Javadocコメントで、変更されることがあることを明記します。
equals()
もApache Commons Langを使っています。まだこのコードはテストしていません。- 処理から除外したい場合はアノテーション
EqualsExclude
を付けると良いみたいです。
- 処理から除外したい場合はアノテーション
hashCode()
もApache Commons Langを使っています。まだこのコードはテストしていません。- 処理から除外したい場合はアノテーション
HashCodeExclude
を付けると良いみたいです。
- 処理から除外したい場合はアノテーション
テスト
equals()のテストには、EqualsVerifierを使うと良さそうです。
処理を追加する場合
- チェック例外を返したい(例外を呼び出し元で処理させたい)場合
- ファクトリーメソッドに例外を付ける。
- テストクラスは、同じパッケージ名で、クラス名の最後に
Test
を付けたものにする。- パッケージプライベートが使用できるため。
- ゲッターは避ける(※検討中)
- テストで必要な場合はパッケージプライベートにする。
- 基本型でなく別のValue Objectを返せないか?
- ゲッターではなく、処理を依頼できないか?
- サービスがふさわしくないか?
- メソッド名に安易に
get
をつけてないか?
-
Effective JavaではnullのときはNullPointerExceptionを投げると良いとされてますが、「引数間違い」という意図を分かりやすくするためにIllegalArgumentExceptionを好んでます。 ↩︎
外部サイト
- Overview (Apache Commons Lang 3.7 API)
- EqualsBuilder (Apache Commons Lang 3.7 API)
- ToStringBuilder (Apache Commons Lang 3.7 API)