【デザインパターン】Facadeを学ぶ【C#】

C#

一言で言うと…

  • 複雑なサブシステムへの統一された窓口を提供し、利用者の手間を減らす仕組み

概要

Facade パターンは、GoF デザインパターンの一つで、構造に関するデザインパターンです。

複数のクラスやサブシステムをまとめ、シンプルな「窓口(Facade)」を提供します。 クライアントは個々のサブシステムの詳細を知らなくても、Facade を通じて簡単に使えるようになります。

ゲーム開発では、複数のマネージャー(サウンド・入力・UI)をまとめてゲーム開始処理を1メソッドで完結させるような場面で役立ちます。

構成

classDiagram
    class Facade {
        - _subsystemA : SubsystemA
        - _subsystemB : SubsystemB
        - _subsystemC : SubsystemC
        + Operation()
    }
    class SubsystemA {
        + OperationA()
    }
    class SubsystemB {
        + OperationB()
    }
    class SubsystemC {
        + OperationC()
    }
    Facade o-- SubsystemA
    Facade o-- SubsystemB
    Facade o-- SubsystemC
    Client ..> Facade : << use >>
要素役割
Facadeサブシステム群への統一窓口。複雑な処理をまとめて提供する
Subsystem個々の処理を担うクラス群。Facade から呼ばれる
ClientFacade だけを使い、サブシステムを意識しない

実装例(C#)

クラス概要

早速実装例です。今回はC#でゲーム開発を行う場合を想定してみました。

利用ケースは以下のように、ゲーム開始時の複雑な初期化処理(音楽・入力・UI)を Facade でまとめる機構です。

  • AudioSystem:BGM再生を担うサブシステム
  • InputSystem:入力受付を担うサブシステム
  • UISystem:UIの初期化を担うサブシステム
  • GameStartFacade:これらをまとめたFacade

ソースコード

1. サブシステム群

C#
using System;
/// <summary>サウンドサブシステム</summary>
public class AudioSystem
{
    public void Initialize() => Console.WriteLine("[Audio] サウンドシステム初期化");
    public void PlayBGM(string trackName) => Console.WriteLine($"[Audio] BGM再生: {trackName}");
}
/// <summary>入力サブシステム</summary>
public class InputSystem
{
    public void Initialize() => Console.WriteLine("[Input] 入力システム初期化");
    public void EnablePlayerInput() => Console.WriteLine("[Input] プレイヤー入力を有効化");
}
/// <summary>UIサブシステム</summary>
public class UISystem
{
    public void Initialize() => Console.WriteLine("[UI] UIシステム初期化");
    public void ShowHUD() => Console.WriteLine("[UI] HUDを表示");
    public void HideLoadingScreen() => Console.WriteLine("[UI] ローディング画面を非表示");
}

2. Facade クラス

C#
/// <summary>
/// ゲーム開始処理のFacade
/// 複数のサブシステムをまとめてシンプルなインターフェースを提供する
/// </summary>
public class GameStartFacade
{
    private readonly AudioSystem _audio;
    private readonly InputSystem _input;
    private readonly UISystem    _ui;
    public GameStartFacade()
    {
        _audio = new AudioSystem();
        _input = new InputSystem();
        _ui    = new UISystem();
    }
    /// <summary>
    /// ゲーム開始に必要な初期化をすべてまとめて実行する
    /// クライアントはこの1メソッドを呼ぶだけでよい
    /// </summary>
    public void StartGame(string stageName)
    {
        Console.WriteLine($"=== {stageName} 開始 ===");
        _audio.Initialize();
        _input.Initialize();
        _ui.Initialize();
        _ui.HideLoadingScreen();
        _ui.ShowHUD();
        _input.EnablePlayerInput();
        _audio.PlayBGM($"{stageName}_BGM");
        Console.WriteLine("=== ゲーム開始完了 ===");
    }
}

3. クライアントコード

C#
class FacadeSample
{
    static void Main()
    {
        // クライアントは Facade を呼ぶだけ
        // サブシステムの詳細を一切知らなくてよい
        var facade = new GameStartFacade();
        facade.StartGame("Forest Stage");
        // => === Forest Stage 開始 ===
        // => [Audio] サウンドシステム初期化
        // => [Input] 入力システム初期化
        // => [UI] UIシステム初期化
        // => [UI] ローディング画面を非表示
        // => [UI] HUDを表示
        // => [Input] プレイヤー入力を有効化
        // => [Audio] BGM再生: Forest Stage_BGM
        // => === ゲーム開始完了 ===
    }
}

使いどころ

  • 複雑な初期化・終了処理を1か所にまとめたいとき
  • サブシステムの内部を外部に公開したくないとき(カプセル化)
  • ライブラリや外部システムへの依存を1か所に集約したいとき

長所・短所

✅ 長所

  • クライアントのコードが大幅にシンプルになる
  • サブシステムの変更をFacadeの内部に隔離できる(変更影響の局所化)
  • レイヤー間の依存を整理でき、アーキテクチャがクリーンになる

⚠️ 短所

  • Facade が肥大化すると「神クラス」になる恐れがある
  • サブシステムの細かい操作が必要な場合、Facade では対応しきれない
  • Facade を経由することで細かい制御が隠蔽されすぎる場合がある

他GoFパターンとの比較・関係

Adapter との違い

Adapter は「インターフェースを変換する」ものです。

Facade は「複数のインターフェースをまとめてシンプルにする」ものです。

Singleton との関係

Facade クラス自体を Singleton にするケースがよくあります。 アプリ全体からアクセスできるシステム窓口として機能します。

Mediator との違い

Mediator はオブジェクト間の通信を仲介します(双方向)。

Facade はクライアントからサブシステムへの一方向のシンプル化です。

まとめ

  • Facade パターンは、複数のサブシステムをまとめてシンプルな窓口を提供する
  • クライアントは Facade の1メソッドを呼ぶだけで複雑な処理を実行できる
  • ゲーム開発ではゲーム開始・終了・シーン遷移などの複合処理に有効
  • Singleton と組み合わせてアプリ全体からアクセスできる設計もよく使われる
  • Facade が肥大化しないよう、責務の分離を意識することが大切
タイトルとURLをコピーしました