Factory MethodパターンのメリットとC#実装例 ― なぜ現場で選ばれるのか Part2

このPart 2は、“理解から実感へ” をテーマに、
「Factoryを使うと何が良くなるのか?」をOCP・保守性・再利用性の観点から
具体的なC#コード例とともに解説します。

目次

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

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

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

    はじめに:Factoryを使わないと何が起こるのか

    次のようなコード、見覚えはありませんか?

    if (type == "PDF")
        report = new PdfReport();
    else if (type == "Excel")
        report = new ExcelReport();
    else if (type == "HTML")
        report = new HtmlReport();
    

    最初はシンプルに見えます。
    しかし、製品(クラス)が増えるたびに if 文も増え、
    やがて「生成処理がアプリ全体に散らばる」状態になります。

    これでは、新しい形式を追加するたびに既存コードを修正しなければなりません。
    つまり、変更に弱い設計です。

    開放閉鎖原則(OCP)とFactory Methodの関係

    OCP(Open-Closed Principle)は

    “拡張には開いていて、修正には閉じている”
    という設計原則です。

    Factory Methodはこの原則を体現する仕組みです。


    ❌ 悪い例:OCP違反の設計

    public class ReportManager
    {
        public IReport CreateReport(string type)
        {
            if (type == "PDF") return new PdfReport();
            if (type == "Excel") return new ExcelReport();
            throw new ArgumentException("不明な形式");
        }
    }
    

    新しいレポート形式 HtmlReport を追加するとき、
    if 文を修正しなければならない=OCP違反です。


    ✅ 改善例:Factory Methodを導入

    // Creator
    public abstract class ReportCreator
    {
        public abstract IReport CreateReport();
    
        public void Execute()
        {
            var report = CreateReport();
            report.Export();
        }
    }
    
    // 具体的なCreator
    public class PdfReportCreator : ReportCreator
    {
        public override IReport CreateReport() => new PdfReport();
    }
    
    public class ExcelReportCreator : ReportCreator
    {
        public override IReport CreateReport() => new ExcelReport();
    }
    

    ここで、新しい製品 HtmlReport を追加しても
    新しいCreatorクラスを1つ作るだけでOK。

    既存コードは一切修正不要です。
    まさに「拡張に開き、修正に閉じた設計」となります。

    🧠 覚えておきたいポイント

    • new を集中管理することで、生成の責務を分離
    • 新しい形式を追加しても、既存ロジックに影響しない
    • クライアントは「何を作るか」ではなく「どう使うか」に専念できる

    再利用性とテスト容易性の向上

    Factory Methodはテストコードにも強いです。
    生成を外部に委ねているため、テスト時には簡単にモックを差し替えられます。


    🎯 テストしやすい構造に変わる

    public class MockReport : IReport
    {
        public void Export() => Console.WriteLine("[Mock] Export 実行");
    }
    
    public class MockCreator : ReportCreator
    {
        public override IReport CreateReport() => new MockReport();
    }
    

    これで、テスト中でも本番と同じフローで動作確認できます。
    ファイル出力や通信処理を避けた軽量テストが可能になります。


    ✅ 実務的な利点

    項目FactoryありFactoryなし
    生成ロジック一元管理コード内に点在
    テストモック差し替え可能実物しか動かせない
    拡張Creator追加のみif文を毎回修正
    保守性高い(影響範囲限定)低い(全体改修が必要)

    C#による標準的なFactory Method実装(基礎形)

    ここで、Factory Methodの基本構造を
    “実務レベルのC#コード”としてまとめておきましょう。

    public interface IReport
    {
        void Export();
    }
    
    public class PdfReport : IReport
    {
        public void Export() => Console.WriteLine("PDFレポートを出力しました。");
    }
    
    public class ExcelReport : IReport
    {
        public void Export() => Console.WriteLine("Excelレポートを出力しました。");
    }
    
    // Creator
    public abstract class ReportCreator
    {
        public abstract IReport CreateReport();
    
        public void Execute()
        {
            var report = CreateReport();
            Console.WriteLine("レポート生成開始...");
            report.Export();
        }
    }
    
    // ConcreteCreatorたち
    public class PdfReportCreator : ReportCreator
    {
        public override IReport CreateReport() => new PdfReport();
    }
    
    public class ExcelReportCreator : ReportCreator
    {
        public override IReport CreateReport() => new ExcelReport();
    }
    
    // 実行
    class Program
    {
        static void Main()
        {
            ReportCreator creator = new PdfReportCreator();
            creator.Execute();
    
            creator = new ExcelReportCreator();
            creator.Execute();
        }
    }
    

    出力結果

    レポート生成開始...
    PDFレポートを出力しました。
    レポート生成開始...
    Excelレポートを出力しました。
    

    このように、共通のCreatorクラスが生成を管理することで、
    新しい形式が増えてもクライアント側は変更不要です。


    Factory Methodがもたらす保守性と安全性

    🔸 責務の分離(SRP)

    Factoryを導入することで、クラスがそれぞれ**単一責務(Single Responsibility)**を持てるようになります。

    • ReportCreator:生成の責務
    • Report(製品):出力処理の責務
    • Client(利用者):利用ロジックの責務

    これにより、変更が入っても他の部分に波及しません。
    結果としてバグの局所化が実現できます。

    🔸 拡張時の安全性

    拡張は新しいCreatorとProductを追加するだけで完了。
    既存クラスの再コンパイルも不要です。
    特に企業システムのような大規模開発では、
    この“変更の独立性”が品質維持に直結します。

    🔸 DI(依存性注入)との親和性

    Factory Methodは DIコンテナと非常に相性が良い です。
    依存関係を IReport として登録しておけば、
    実行時に PdfReport でも ExcelReport でも柔軟に切り替え可能。

    services.AddTransient<IReport, PdfReport>();
    

    Factoryによる抽象化を活かすことで、
    アプリ全体の依存関係がクリーンになります。

    まとめ:Factory Methodは“成長するコード”の基礎

    Factory Methodを導入すると、

    • コードが拡張に強くなる(OCP準拠)
    • 責務が明確になり保守が容易になる
    • テストがしやすくなる

    つまりこれは、「長く使えるコード」へ成長させるための設計です。

    覚えておきたい一文:
    Factory Methodは「変更を追加に変える」ための設計。
    新しい要件が来ても、“既存コードを壊さず”に進化できる。

    次回予告:Factory MethodをモダンC#で最適化する

    次回(Part 3)では、最新C#構文を活用してFactoryをより型安全・簡潔・柔軟に進化させる方法を紹介します。

    • ジェネリクスによる型安全化
    • new()簡略構文とswitch式
    • DI(依存性注入)との統合
    • Factory Registryによる柔軟拡張
    よかったらシェアしてね!
    • URLをコピーしました!
    • URLをコピーしました!
    目次