導入
前章でTaskItemはnew TaskItem(id, new TaskTitle(title), priority)という形で作れるようになりました。ですが、この呼び出しを「タスク追加の画面」「サンプルデータの読み込み」「テストコード」など、あちこちに書き散らかすとどうなるでしょうか。あとで「IDの発行ルールを変えたい」「優先度の既定値をMEDIUMからLOWに変えたい」となったとき、全ての呼び出し箇所を探して直すはめになります。Factoryは、この「生成のルール」を1か所に閉じ込めるパターンです。
図解
flowchart TB
subgraph S["Factoryが無い場合"]
A1["画面のコード<br/>new TaskItem(nextId(), new TaskTitle(t), Priority.MEDIUM)"]
A2["インポート機能のコード<br/>new TaskItem(nextId(), new TaskTitle(t), Priority.MEDIUM)"]
A3["テストのコード<br/>new TaskItem(nextId(), new TaskTitle(t), Priority.MEDIUM)"]
end
subgraph T["Factoryがある場合"]
F["TaskFactory#create<br/>(検証・ID発行のルールを1か所に)"]
B1["画面のコード<br/>factory.create(t)"] --> F
B2["インポート機能のコード<br/>factory.create(t)"] --> F
B3["テストのコード<br/>factory.create(t)"] --> F
end
生成のパターンそのもの(Factory Method / Abstract Factory)の詳しい解説はC#デザインパターンコースのレッスン1にあります。ここでは「タスク管理アプリのどこで使うと嬉しいか」に絞って確認します。
説明
public class Person {
private final String id;
private final String name;
private final int age;
public Person(String id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public String getId() { return id; }
public String getName() { return name; }
public int getAge() { return age; }
}
public class PersonFactory {
private static int nextId = 1;
public static Person create(String name, int age) {
if (age < 0) throw new IllegalArgumentException("年齢は0以上です");
return new Person(String.valueOf(nextId++), name.trim(), age);
}
}
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class PersonFactoryTest {
@Test
void zengoNoKuhaku_HaTrimSareru() {
Person p1 = PersonFactory.create(" 田中 ", 30);
assertEquals("田中", p1.getName(), "前後の空白はトリムされる(決め事を1か所に)");
}
@Test
void idNoHakkoRule_Mo1KashoNiMatomatteiru() {
Person p1 = PersonFactory.create("田中", 30);
Person p2 = PersonFactory.create("鈴木", 25);
assertNotEquals(p2.getId(), p1.getId(), "IDの発行ルールも1か所にまとまっている");
}
}
new Person(...)の呼び出しはPersonFactory.createの中に1か所だけ- 「IDをどう払い出すか」「前後の空白をトリムする」「年齢は0以上」という決め事も1か所にまとまっている
- 呼び出し側は
PersonFactory.create(name, age)と書くだけでよく、生成の詳細を知らなくてよい
まとめ
- Factoryは「
newの呼び出し」と「生成時の決め事(検証・ID発行・トリムなど)」を1か所に集約するパターン - 呼び出し側はコンストラクタの詳細を知らなくても、正しい状態のオブジェクトを作れる
- 次のレッスンでは、実際に
TaskFactoryをTDDで実装する
次回: 実際にTaskFactory.createをTDDで実装します。