Factory Methodパターンとは?C#で学ぶオブジェクト生成の基本構造 Part1

目次

はじめに:直接newするコードがなぜ問題になるのか

C#で開発していると、ついこう書いてしまうことがあります。

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

動きはしますが、少しずつ条件が増えると大変なことになります。
「新しいレポート形式を追加したい」となるたびに
このコードを修正しなければならない──。

このような構造は“変更に弱い”コードと呼ばれます。
プロジェクトが成長するほど、if 文や new が増え、
やがてバグの温床になります。

そんな「生成の混乱」を解消するのが、Factory Methodパターンです。

Factory Methodパターンとは何か

Factory Methodパターンとは、

「どのクラスを生成するかをサブクラスに任せる」
設計パターンです。

もう少し簡単に言えば、
オブジェクトを作る責任を、使う側ではなく“専門の工場”に分ける」仕組みです。

💬 日常の例で考えてみましょう

例えば、あなたが“車”を必要としているとします。
あなたは車を「作る」より「使う」ことに集中したいはず。
実際の製造(トヨタ・ホンダ・スズキ)はそれぞれが担当します。

同じように、ソフトウェアでも「生成の責務」を分けることで、
利用側のコードを安定化させることができます。

パターンを構成する4つの要素

Factory Methodパターンは、4つの主要クラスで構成されます。

要素役割C#での表現例
Product製品の共通インターフェースIReport
ConcreteProduct実際の製品クラスPdfReport, ExcelReport
Creator生成を定義する抽象クラスReportCreator
ConcreteCreator実際に製品を生成するクラスPdfReportCreator, ExcelReportCreator

構造を図で表すと以下のようになります:

Creator ── Create() ──▶ Product
   ▲                        ▲
   ├─ ConcreteCreatorA → ConcreteProductA
   └─ ConcreteCreatorB → ConcreteProductB

Creator(工場)は「作る手順」を定義し、
実際に「何を作るか」はサブクラス(ConcreteCreator)が決めます。

最小のC#実装で理解するFactory Method

では、実際に動く最小のサンプルを見てみましょう。

// 製品の共通インターフェース
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();
        report.Export();
    }
}

// 具体的Creator
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();  // PDFレポートを出力しました。

        creator = new ExcelReportCreator();
        creator.Execute();  // Excelレポートを出力しました。
    }
}

出力結果

PDFレポートを出力しました。
Excelレポートを出力しました。

このパターンが活きる場面

Factory Methodパターンは、「生成対象が複数ある」「拡張される可能性が高い」
そんな場面で特に力を発揮します。

よくある3つの実例

  1. GUIアプリ
     → OSやテーマごとに異なるボタン/ウィンドウを生成
  2. データベースアクセス
     → SQLServer/MySQL/PostgreSQL 用クライアントを切り替え
  3. AIモデル選択
     → GPT/Claude/Gemini などを実行時に選択

これらは、どの製品を使うかをサブクラスに委ねるだけで差し替えが完了します。
クライアントコードは new を知らないので、変更に強く保守しやすい構造になります。

Factory Methodを使うメリット(簡単な先取り)

詳細は次回記事で詳しく解説しますが、
この設計を導入すると以下の効果が得られます。

メリット内容
拡張性新しい製品を追加しても既存コードに影響なし
保守性「生成の責務」を1か所に集約できる
再利用性Creatorを共通化して異なる製品に流用可能

まとめ:生成の責務を分離するとコードが変わる

Factory Methodパターンは、
**「生成を分離してコードの柔軟性を高める」**設計思想です。

実務では「複数のバリエーションを扱うクラス」ほど、
このパターンの恩恵を受けやすくなります。

覚えておきたい一文:
Factory Methodは「どんなものを作るか」をサブクラスに委ねるための設計
利用側はただ「作って使う」だけに集中できます。


次回予告:Factory Methodはなぜ現場で使われるのか?

次の記事では、

  • OCP(開放閉鎖原則)
  • 再利用性・テスト容易性
  • 標準的なC#実装の流れ

を通して、Factory Methodが「現場で選ばれる理由」を掘り下げていきます。

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