#03 / 23
C生成DIFF
抽象ファクトリ
Abstract Factory
『北欧スタイルで全部揃えて』──ソファとテーブルとランプを別々の店で買わずに、テーマで一括コーデする家具屋さん。
Intent · 目的
互いに関連したオブジェクト群を、具象クラスを意識させずに『セットで』生成するインタフェースを提供する。クライアントは抽象ファクトリだけを参照し、ファミリ全体(テーマ)を一括で切り替えられる。
Motivation · 動機
想像してほしい。ダークテーマのアプリで、ボタンだけうっかり Light 用を `new` してしまった画面。1個だけ眩しく光って、世界観が崩壊する。OS別UI、開発/本番のリソース、ゲームのワールド観 ── 『揃ってないと違和感』が出るオブジェクト群は、個別生成では混在事故が起きる。抽象ファクトリは『テーマを選んだら、配下のパーツは全部それで揃う』という保証を与えてくれるコーディネーター。
適用場面
- 1互いに関連した複数種類のオブジェクトをまとめて差し替えたい場合(テーマ、OS、環境)。
- 2ファミリ間で混ぜてはいけない一貫性制約がある場合(DarkButton と LightCheckbox は混ぜるな危険)。
- 3クライアントを具象クラスから完全に隔離したい場合。
概念図
サンプルコード
interface Button { render(): void; }
interface Checkbox { render(): void; }
class DarkButton implements Button { render(){ console.log("[dark] button"); } }
class DarkCheckbox implements Checkbox { render(){ console.log("[dark] checkbox"); } }
class LightButton implements Button { render(){ console.log("[light] button"); } }
class LightCheckbox implements Checkbox { render(){ console.log("[light] checkbox"); } }
interface GUIFactory {
createButton(): Button;
createCheckbox(): Checkbox;
}
class DarkFactory implements GUIFactory {
createButton(){ return new DarkButton(); }
createCheckbox(){ return new DarkCheckbox(); }
}
class LightFactory implements GUIFactory {
createButton(){ return new LightButton(); }
createCheckbox(){ return new LightCheckbox(); }
}
const f: GUIFactory = new DarkFactory();
f.createButton().render();
f.createCheckbox().render();Pros · メリット
- +ファミリを丸ごと差し替えられる ── テーマ切替が1行で済む。
- +「Dark なのにボタンだけ Light」みたいな混在事故を、設計レベルで防げる。
- +クライアントはどの具象クラスも知らない。新テーマの追加で利用側に手は入らない。
Cons · デメリット
- −ファミリに新しい『種類』(例: スライダー追加) を足すと、全ファクトリの修正が必要。種類軸の拡張に弱い。
- −クラス数が一気に増える。テーマが2種類しかない時点で導入するのは過剰。
- −セットを増やすたびに具象ファクトリも1個増えるので、爆発しやすい。
関連パターン
⚔ ready to test
理解度を確かめる時間だ
3 問のクイズで、 このパターンを身体に染み込ませよう。