導入
業務データを表す型には、大きくEntityと値オブジェクトの2種類があります。Entityは「同じ内容でもIDで区別される」もの――たとえば同姓同名の別人は別人として扱われます。タスク管理アプリの中心となるEntity、TaskItemを作りながらこの感覚を掴みましょう。
図解
flowchart LR
subgraph E["Entity: 同一性はIDで決まる"]
A["Book(id="1", title="Java入門")"]
B["Book(id="2", title="Java入門")"]
end
A -. 内容は同じでも別物 .- B
サンプル
実務ならBookは呼び出し側とは別のBook.javaに置きます。
public class Book {
private final String id;
private final String title;
public Book(String id, String title) {
this.id = id;
this.title = title;
}
public String getId() { return id; }
public String getTitle() { return title; }
}
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class BookTest {
@Test
void idGaChigaeba_BetsuNoBookToShiteAtsukau() {
Book book1 = new Book("1", "Java入門");
Book book2 = new Book("2", "Java入門");
assertNotEquals(book2.getId(), book1.getId(), "IDが違えば別のBook");
assertEquals(book2.getTitle(), book1.getTitle(), "中身(title)が同じでも別物としてよい");
}
}
- Entityは「IDが違えば、内容が同じでも別のもの」として扱う
- 逆に言えば、Entityにとって一番大事な情報はIDである
- フィールドは
private finalにし、外からはgetXxx()(ゲッター)でしか読めないようにするのがJavaの慣習
やってみよう
下のエディタにはTaskItem.java(実装)とTaskItemTest.java(テスト)の2つのタブがあります。まず何も書かずに「▶ 実行」を押してみてください。テストが赤(❌)になるのがRedの状態です。
演習
タスク管理アプリのEntity、TaskItemの一番最初の形をTDDで作ります。id(String)・title(String)・completed(boolean、既定false)を持つクラスです。実装はTaskItem.java、テストはTaskItemTest.javaという別ファイルに分けて書きましょう(画面上部のタブで切り替えられます)。
public class TaskItem {
// TODO: id(String)・title(String)・completed(boolean、既定false)を持つ
// TaskItem クラスを実装してください(コンストラクタは id と title を受け取る)
// getId() / getTitle() / isCompleted() というゲッターも用意します
}
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class TaskItemTest {
@Test
void idGaChigaeba_BetsuNoTaskToShiteAtsukau() {
TaskItem t1 = new TaskItem("1", "牛乳を買う");
TaskItem t2 = new TaskItem("2", "牛乳を買う");
assertNotEquals(t2.getId(), t1.getId(), "IDが違えば別のタスク");
}
@Test
void titleWoHojishiteiru() {
TaskItem t1 = new TaskItem("1", "牛乳を買う");
assertEquals("牛乳を買う", t1.getTitle(), "titleを保持している");
}
@Test
void sakuseiChokugoHaMikanryo() {
TaskItem t1 = new TaskItem("1", "牛乳を買う");
assertFalse(t1.isCompleted(), "作成直後は未完了");
}
}
- 期待される結果: 3件のテストがすべて成功
ヒント1を見る
TaskItem.javaに実装します。public class TaskItem { private final String id; private final String title; private boolean completed; public TaskItem(String id, String title) { this.id = id; this.title = title; } public String getId() { return id; } public String getTitle() { return title; } public boolean isCompleted() { return completed; } }
ヒント2を見る
completedはbooleanの既定値falseのまま初期化すれば条件を満たします。boolean型のゲッターはisXxx()という名前にするのがJavaの慣習です
まとめ
- EntityはIDで区別される。内容(title等)が同じでも別物になりうる
TaskItemはid・title・completedを持つクラスとして最初の形を作った- 次はタイトルの検証ルールを持つ
TaskTitle(値オブジェクト)を作り、Stringの代わりに使えるようにする
次回: 値そのものが同一性を持つ値オブジェクト ― TaskTitleです。