モダンC#で進化するFactory Method ― ジェネリクスとDIによる設計最適化 Part3

このPart 3では、前回の「理解」から一歩進み、
モダンC#構文(C#10〜12)を使ってFactoryをより型安全・シンプル・柔軟に最適化する方法を解説します。

目次

受講者数No.1!初心者からプロへ導く信頼のスクール

    短期間で習得可能!未経験から実践力を磨く充実のプログラム

    今なら無料相談でAmazonギフトカードがもらえる!

    はじめに:昔のFactoryと今のFactoryの違い

    Factory Methodパターンは1990年代に生まれた設計手法ですが、
    C#の進化によって“より短く、より安全に”書ける時代になりました。

    古いコードでは、こうしたFactoryがよくありました。

    public abstract class Creator
    {
        public abstract IReport CreateReport();
    }
    

    ここで毎回 IReport 型を返すため、
    キャストや冗長なクラス宣言が増えがちです。

    しかし、C# 10以降では ジェネリクス・式ボディ・new()簡略構文・switch式 などにより、
    Factoryのコードを半分以下にできます。


    ジェネリクスで型安全なCreatorを実現する

    ジェネリクスを導入すると、Creatorが生成する型を明確に制約できます。

    // Creator<T>:型安全な抽象Creator
    public abstract class Creator<T> where T : IReport
    {
        public abstract T CreateReport();
    
        public void Execute()
        {
            var report = CreateReport();
            Console.WriteLine($"[{report.GetType().Name}] を生成しました。");
            report.Export();
        }
    }
    

    where T : IReport により、
    Creatorが扱えるのは「IReportを実装する型」に限定されます。
    → キャスト不要、型安全、IDE補完も効く。

    具体的Creator(ジェネリクス対応)

    public class PdfCreator : Creator<PdfReport>
    {
        public override PdfReport CreateReport() => new();
    }
    
    public class ExcelCreator : Creator<ExcelReport>
    {
        public override ExcelReport CreateReport() => new();
    }
    

    new() の簡略構文を使えば、生成もワンライン。
    C# 10 以降では、明示的な型記述すら不要です。


    実行例

    class Program
    {
        static void Main()
        {
            var pdfCreator = new PdfCreator();
            pdfCreator.Execute();
    
            var excelCreator = new ExcelCreator();
            excelCreator.Execute();
        }
    }
    

    出力結果:

    [PdfReport] を生成しました。
    PDFレポートを出力しました。
    [ExcelReport] を生成しました。
    Excelレポートを出力しました。
    

    モダン構文でFactoryをシンプルにする

    モダンC#の特徴を取り入れると、Factoryはより洗練されます。

    機能使用例効果
    式ボディメソッドpublic override PdfReport CreateReport() => new();可読性・短縮性UP
    new() 簡略構文new();型名省略で安全な省略
    switch式key switch { "PDF" => new PdfCreator(), ... }条件分岐の明示化
    record型record ReportConfig(string Type, string Path);Factory登録情報を簡潔に表現

    パターンマッチングによるCreator選択

    Factoryを動的に選ぶ際にも、
    C#の switch 式を使うと柔軟で読みやすくなります。

    static Creator<IReport> SelectCreator(string key) => key switch
    {
        "PDF" => new PdfCreator(),
        "Excel" => new ExcelCreator(),
        _ => throw new ArgumentException("不明なレポート形式")
    };
    

    旧来のif/elseに比べて、
    構造的に安全でミスが起きにくいコードになります。

    DI(依存性注入)とFactoryの統合

    モダンC#でFactoryを使う最大の強みは、DIコンテナとの統合です。
    ASP.NET Coreでは IServiceCollection に登録するだけで、
    Creatorを実行時に差し替え可能になります。

    services.AddTransient<Creator<PdfReport>, PdfCreator>();
    services.AddTransient<Creator<ExcelReport>, ExcelCreator>();
    

    利用側は依存を抽象型で受け取るだけ:

    public class ReportService
    {
        private readonly Creator<IReport> _creator;
    
        public ReportService(Creator<IReport> creator)
        {
            _creator = creator;
        }
    
        public void Run() => _creator.Execute();
    }
    

    これにより、アプリ全体の構成変更を「設定」だけで完結できるようになります。

    Factory Registryで柔軟な拡張構造を実現する

    「製品が増えすぎてCreatorクラスが多くなった」場合は、
    Factoryをレジストリ形式(辞書管理)に変えると柔軟性が上がります。

    public static class ReportFactoryRegistry
    {
        private static readonly Dictionary<string, Func<IReport>> _registry = new()
        {
            { "PDF", () => new PdfReport() },
            { "Excel", () => new ExcelReport() }
        };
    
        public static IReport Create(string key)
        {
            if (_registry.TryGetValue(key, out var factory))
                return factory();
            throw new ArgumentException($"不明な形式: {key}");
        }
    }
    

    利用例

    IReport report = ReportFactoryRegistry.Create("PDF");
    report.Export();
    

    Creatorクラスを持たないこの構造は、
    “Simple Factory”と“Factory Method”の中間形で、
    小規模アプリではとても有効です。


    実務応用:AI・Web・ゲームでも使われるFactory Method

    Factory Methodは「生成責務を分離する」という発想ゆえ、
    多様な領域で活躍しています。

    分野具体例Factoryの役割
    AI/MLアプリGPT・Geminiなどモデル切替モデル生成をFactoryで統一
    Web APIクライアント認証(Basic / OAuth)認証タイプごとにCreator切替
    ゲーム開発Unityでのエフェクト・敵生成Prefab生成をFactory化して一元管理

    特に、依存の切替やプラグイン拡張が必要な環境では、
    Factory Methodが保守コストを劇的に下げます。


    まとめ:Factory Methodは今も“現役の設計”

    Factory Methodは古い概念に見えて、
    現代のC#アプリケーション設計でも中核的存在です。

    ✅ 今回の要点

    • ジェネリクスで型安全なCreatorを実現
    • new() 簡略構文・switch式で冗長性を削減
    • DIと統合して拡張性を最大化
    • Factory Registryで軽量な柔軟拡張も可能

    結論:
    Factory Methodは「拡張を前提とした設計」を支える最もシンプルなパターン。
    それを現代C#の文法で磨くことで、
    短く・安全で・保守に強いコードが生まれる。

    よかったらシェアしてね!
    • URLをコピーしました!
    • URLをコピーしました!
    目次