この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による柔軟拡張


