本文へスキップ
BecomeCoder

C#デザインパターンコース · 第1章 デザインパターン · レッスン7

構造③:Facade / Flyweight / Proxy

ブラウザで完結

導入

Facadeは「複雑なサブシステムに、単純な窓口を1つ提供」。Flyweightは「大量の同一データを共有して省メモリに」。Proxyは「本物への代理を立て、アクセス制御やキャッシュを挟む」。いずれも“間に1枚かませる”パターンです。

図解

flowchart LR
    U["利用側"] --> FA["Facade(単純な窓口)"]
    FA --> S1["複雑な部品A"]
    FA --> S2["複雑な部品B"]
    style FA fill:#e1f5fe

サンプル

Facadeは「窓口ファイル」、Proxyは「本物と同じ形をした代理ファイル」。分けて置くと、利用側がどちらを見ているかがはっきりします。

1. サービスの共通の形(IService.cs)。本物も代理もこの形を実装します。

public interface IService
{
    void Run();
}

2. 本物(RealService.cs)。Proxyのことを何も知りません。

public class RealService : IService
{
    public void Run() => Console.WriteLine("本処理を実行");
}

3. 代理(LoggingProxy.cs)。本物と**同じIService**なので、利用側のコードを1行も変えずに差し込めます。

// Proxy: 本物へのアクセス前にログ(や権限チェック・キャッシュ)を挟む
public class LoggingProxy : IService
{
    private readonly IService _real;
    public LoggingProxy(IService real) => _real = real;
    public void Run()
    {
        Console.WriteLine("[ログ] 呼び出し前");
        _real.Run();   // 本物へ委譲
    }
}

4. 窓口(HomeTheaterFacade.cs)。複数の部品の手順を1つのメソッドに畳み込みます。

// Facade: 複雑な内部の手順を1つの簡単な操作にまとめる
public class HomeTheaterFacade
{
    public void WatchMovie()
    {
        Console.WriteLine("スクリーンを下ろす");
        Console.WriteLine("プロジェクタON");
        Console.WriteLine("再生開始");
    }
}

5. 利用側(Program.cs)。new RealService() を new LoggingProxy(new RealService()) に変えるだけ、が体験できます。

var home = new HomeTheaterFacade();
home.WatchMovie();   // スクリーンを下ろす / プロジェクタON / 再生開始

IService service = new LoggingProxy(new RealService());
service.Run();       // [ログ] 呼び出し前 / 本処理を実行
  • Facade: 複雑な内部を隠し、単純な入り口を提供する(WatchMovie一発)
  • Flyweight: 同じ値を使い回して共有し、メモリを節約する(文字フォント等)
  • Proxy: 本物の代理として、ログ・権限・遅延ロード・キャッシュを挟む
  • 代理を外したいときはProgram.csの1行を戻すだけ。ほかのファイルは無傷

演習

IImage img = new LazyImageProxy("photo.jpg");
Console.WriteLine("まだ読み込まれない");
img.Display();   // 読み込み: photo.jpg / 表示: photo.jpg

// TODO: Display() が呼ばれて初めて "読み込み: ファイル名" を出す遅延ロードの
//       LazyImageProxy を定義してください(Display で読み込み→表示の順に出力)
interface IImage { void Display(); }
___
  • 期待される出力: まだ読み込まれない 読み込み: photo.jpg 表示: photo.jpg(3行)
ヒント1を見る

Displayの中で「読み込み」出力→「表示」出力の順にします

ヒント2を見る

class LazyImageProxy : IImage { private readonly string _file; public LazyImageProxy(string file) => _file = file; public void Display() { Console.WriteLine($"読み込み: {_file}"); Console.WriteLine($"表示: {_file}"); } }

まとめ

  • Facadeは複雑な内部への単純な窓口
  • Flyweightは同一データの共有で省メモリ
  • Proxyは本物の代理でアクセス制御・遅延・キャッシュを挟む

次回: 振る舞いパターンへ。アルゴリズムと状態のStrategy/Stateです。

実際に動かしてみよう

このレッスンのサンプルは、実務と同じように役割ごとの .cs ファイルへ分けてあります。下のエディタは最初からその複数ファイルが入った状態で、上のタブでファイルを切り替えられます。そのまま「▶ 実行」を押せば全ファイルをまとめてコンパイルして動かせるので、クラスを足したりファイルをまたいで書き換えたりしながら進めましょう(演習は本文のコードをコピーして Program.cs のタブに貼り付ければ試せます)。

C# — ブラウザ内で実行

ブラウザ内でC#を動かす環境を読み込みます(初回のみ数秒)。
スクロールして表示された時点でも自動で読み込まれます。

次のレッスンへ →