導入
生成に関するパターンは「オブジェクトの作り方」を工夫します。Factory Methodは「どのクラスを作るかを1か所に集約」し、Abstract Factoryは「関連する部品一式をまとめて生成」します。newを呼び出し側から隠すのが共通の狙いです。
図解
flowchart TB
C["呼び出し側"] -->|種類を渡すだけ| F["Factory<br/>どの具体クラスを new するか決める"]
F --> P1["Circle"]
F --> P2["Square"]
style F fill:#e1f5fe
サンプル
// Factory Method: 生成の判断を工場メソッドに集約
IShape shape = ShapeFactory.Create("circle");
shape.Draw(); // ○を描く
// Abstract Factory: 関連部品一式(ボタン+チェックボックス)をまとめて生成
IUIFactory factory = new DarkFactory();
Console.WriteLine(factory.CreateButton()); // [ダークボタン]
Console.WriteLine(factory.CreateCheckbox()); // [ダークチェック]
interface IShape { void Draw(); }
class Circle : IShape { public void Draw() => Console.WriteLine("○を描く"); }
class Square : IShape { public void Draw() => Console.WriteLine("□を描く"); }
static class ShapeFactory
{
public static IShape Create(string kind) => kind switch
{
"circle" => new Circle(),
"square" => new Square(),
_ => throw new ArgumentException("未知の図形"),
};
}
interface IUIFactory { string CreateButton(); string CreateCheckbox(); }
class DarkFactory : IUIFactory
{
public string CreateButton() => "[ダークボタン]";
public string CreateCheckbox() => "[ダークチェック]";
}
- Factory Method:
newの分岐を工場メソッドに集約し、呼び出し側は種類を指定するだけ - Abstract Factory: 一貫性のある部品群(例: ダークテーマ一式)をまとめて作る
- どちらも「具体クラスへの依存」を呼び出し側から切り離す
演習
IAnimal a = AnimalFactory.Create("dog");
a.Cry(); // ワン
// TODO: "dog"→Dog(Cry→"ワン"), "cat"→Cat(Cry→"ニャー") を生成する
// ShapeFactory 風の AnimalFactory.Create を完成させてください
interface IAnimal { void Cry(); }
class Dog : IAnimal { public void Cry() => Console.WriteLine("ワン"); }
class Cat : IAnimal { public void Cry() => Console.WriteLine("ニャー"); }
___
- 期待される出力:
ワン
ヒント1を見る
static class AnimalFactory { public static IAnimal Create(string k) => k switch { "dog" => new Dog(), "cat" => new Cat(), _ => throw new ArgumentException() }; }
ヒント2を見る
switch式で種類ごとにnewを返します
まとめ
- Factory Methodは生成の判断を1か所に集約する
- Abstract Factoryは関連部品一式をまとめて生成する
- 呼び出し側を具体クラスから切り離す
次回: 複雑な生成を段階的に組み立てるBuilderです。