導入
業務データを表す型には、大きくEntityとValueObjectの2種類があります。Entityは「同じ内容でもIDで区別される」もの——たとえば同姓同名の別人は別人として扱われます。タスク管理アプリの中心となるEntity、TaskItemを作りながらこの感覚を掴みましょう。
図解
flowchart LR
subgraph E["Entity: 同一性はIDで決まる"]
A["Book(Id=1, Title="C#入門")"]
B["Book(Id=2, Title="C#入門")"]
end
A -. 内容は同じでも別物 .- B
サンプル
var book1 = new Book(1, "C#入門");
var book2 = new Book(2, "C#入門");
Assert(book1.Id != book2.Id, "IDが違えば別のBook");
Assert(book1.Title == book2.Title, "中身(Title)が同じでも別物としてよい");
Console.WriteLine("全テスト成功");
class Book
{
public int Id { get; }
public string Title { get; }
public Book(int id, string title) { Id = id; Title = title; }
}
void Assert(bool condition, string name)
{
if (!condition) throw new Exception($"FAIL: {name}");
}
- Entityは「IDが違えば、内容が同じでも別のもの」として扱う
- 逆に言えば、Entityにとって一番大事な情報はIDである
- 今はまだ
Idの型にintを使っているが、実務では衝突しにくいGuid(第9章まで使い続ける型)を使うことが多い
演習
タスク管理アプリのEntity、TaskItemの一番最初の形をTDDで作ります。Id(Guid)・Title(string)・IsCompleted(bool、既定false)を持つクラスです。
var t1 = new TaskItem(Guid.NewGuid(), "牛乳を買う");
var t2 = new TaskItem(Guid.NewGuid(), "牛乳を買う");
Assert(t1.Id != t2.Id, "IDが違えば別のタスク");
Assert(t1.Title == "牛乳を買う", "Titleを保持している");
Assert(t1.IsCompleted == false, "作成直後は未完了");
Console.WriteLine("全テスト成功");
// TODO: Id(Guid)・Title(string)・IsCompleted(bool、既定false)を持つ
// TaskItem クラスを実装してください(コンストラクタは id と title を受け取る)
void Assert(bool condition, string name)
{
if (!condition) throw new Exception($"FAIL: {name}");
}
___
- 期待される出力:
全テスト成功
ヒント1を見る
class TaskItem { public Guid Id { get; } public string Title { get; } public bool IsCompleted { get; private set; } public TaskItem(Guid id, string title) { Id = id; Title = title; } }
ヒント2を見る
IsCompletedは自動プロパティの既定値falseのままで条件を満たします
まとめ
- EntityはIDで区別される。内容(Title等)が同じでも別物になりうる
TaskItemはId・Title・IsCompletedを持つクラスとして最初の形を作った- 次はタイトルの検証ルールを持つ
TaskTitle(ValueObject)を作り、stringの代わりに使えるようにする
次回: 値そのものが同一性を持つValueObject― TaskTitleです。