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


はじめに:昔の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#の文法で磨くことで、
短く・安全で・保守に強いコードが生まれる。

