【デザインパターン】Abstract Factoryを学ぶ【C#】

C#

一言で言うと…

  • 関連オブジェクト群をまとめて生成し、一貫性を保つ仕組み

概要

Abstract Factory パターンは、GoF デザインパターンの一つで、生成に関するデザインパターンです。

複数の関連するオブジェクトを、抽象的なインターフェース(Factory)を介して一括生成する仕組みを提供します。

責務を適切に分離することで、以下の利点が得られます:

  • クライアント側は具体的なクラスを意識せずに利用できる
  • 生成されるオブジェクト群の一貫性を保証できる

構成

classDiagram
   direction BT
    namespace factory {
   class IFactory {
      << interface >>
   }
   class ConcreteFactory
}
   ConcreteFactory ..|> IFactory : implements

   namespace product {
   class Product1 {
      << abstract >>
   }
   class Product2 {
      << abstract >>
   }

   class ConcreteProduct1
   class ConcreteProduct2
}

   ConcreteProduct1 --|> Product1 : extends
   ConcreteProduct2 --|> Product2 : extends

   IFactory ..> Product1
   IFactory ..> Product2
   Client ..> IFactory : << use >>

実装例(C#)

クラス概要

早速実装例です。今回はC#でゲーム開発を行う場合を想定してみました。

利用ケースは以下のように、ステージごとに異なるボスとお宝を生成する機構です。

  • Boss / Treasure:抽象プロダクト (Product)
  • ForestBoss / GoldenChest, DesertBoss / SandChest:具象プロダクト (Concrete Product)
  • IStageFactory:抽象ファクトリ (IFactory)
  • ForestStageFactory / DesertStageFactory:具象ファクトリ (Concrete Factory)
  • クライアント:生成されたプロダクトを保持し利用する

ソースコード

1. 抽象プロダクト (Product)

C#
/// <summary>
/// ボス抽象クラス (Product)
/// </summary>
public abstract class Boss
{
    public abstract void Appear();
}

/// <summary>
/// お宝抽象クラス (Product)
/// </summary>
public abstract class Treasure
{
    public abstract void Reveal();
}

これはステージに登場するボスとお宝の抽象クラスです。Abstract Factory パターンの Product に位置します。

2. 具象プロダクト (Concrete Product)

C#
using System;

public class ForestBoss : Boss
{
    public override void Appear() => Console.WriteLine("森のボスが出現した!");
}

public class GoldenChest : Treasure
{
    public override void Reveal() => Console.WriteLine("黄金の宝箱が現れた!");
}

public class DesertBoss : Boss
{
    public override void Appear() => Console.WriteLine("砂漠のボスが出現した!");
}

public class SandChest : Treasure
{
    public override void Reveal() => Console.WriteLine("砂の宝箱が現れた!");
}

これらのクラスはボスとお宝の具象クラスです。Abstract Factory パターンの Concrete Product に位置します。

今回、ボスは森と砂漠ステージ用の2種類、宝箱は黄金と砂の2種類を用意しました。

3. 抽象ファクトリ (IFactory)

C#
/// <summary>
/// 抽象ファクトリ (IFactory)
/// </summary>
public interface IStageFactory
{
    Boss CreateBoss();
    Treasure CreateTreasure();
}

これはプロダクト生成を行うファクトリのインタフェースです。Abstract Factory パターンの IFactory に位置します。

4. 具象ファクトリ (Concrete Factory)

C#
public class ForestStageFactory : IStageFactory
{
    public Boss CreateBoss() => new ForestBoss();
    public Treasure CreateTreasure() => new GoldenChest();
}

public class DesertStageFactory : IStageFactory
{
    public Boss CreateBoss() => new DesertBoss();
    public Treasure CreateTreasure() => new SandChest();
}

これらのクラスはプロダクトの生成を行うファクトリの具象クラスです。Abstract Factory パターンの Concrete Factory に位置します。

今回は森と砂漠ステージのファクトリを用意しました。

5. クライアントコード

C#
using System;

/// <summary>
/// クライアント
/// </summary>
public class Stage
{
    private readonly Boss _boss;
    private readonly Treasure _treasure;

    public Stage(IStageFactory factory)
    {
        _boss = factory.CreateBoss();
        _treasure = factory.CreateTreasure();
    }

    public void Enter()
    {
        Console.WriteLine("ステージに突入!");
        _boss.Appear();
        _treasure.Reveal();
    }
}

class AbstractFactorySample
{
    static void Main()
    {
        // 森ステージ
        IStageFactory forestFactory = new ForestStageFactory();
        Stage forestStage = new Stage(forestFactory);
        forestStage.Enter();
        // => ステージに突入!
        // => 森のボスが出現した!
        // => 黄金の宝箱が現れた!

        // 砂漠ステージ
        IStageFactory desertFactory = new DesertStageFactory();
        Stage desertStage = new Stage(desertFactory);
        desertStage.Enter();
        // => ステージに突入!
        // => 砂漠のボスが出現した!
        // => 砂の宝箱が現れた!
    }
}

これはクライアントコードの例です。各ステージを生成する場面を想定しています。

クライアント側は抽象プロダクトの参照だけ持っていて、実行例で注入した具象ファクトリにより処理が分岐します。

使いどころ

  • ある分類ごとに「関連するオブジェクト群」をまとめて生成・管理したいとき
  • クライアント側で具象クラスに依存せずに関連オブジェクト群を切り替えたいとき

長所・短所

✅ 長所

  • ファクトリから得られるプロダクト同士の互換性の保証
  • 具象プロダクト群とクライアント側の密結合を回避
  • プロダクト作成処理が一か所(ConcreteFactory)にまとめられ、保守が容易。(単一責任の原則)
  • プロダクトの新しい型を導入しても、既存の機能に影響しない。(開放閉鎖の原則)

⚠️ 短所

  • サブクラスが増えるため、クラス数が多くなる
  • 小規模な場合は過剰設計になる可能性がある

まとめ

Abstract Factory パターンは、ステージ・ボス・宝物のような関連オブジェクト群をまとめて生成したい場合に特に有効です。
テーマごとに統一された組み合わせを作れるため、ゲーム開発でのステージ設計や拡張性に強い構造を提供します。

ぜひ試してみてください!

タイトルとURLをコピーしました