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

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

目次

はじめに: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をコピーしました!
目次