概要
Proxy パターンは、GoF デザインパターンの一つで、構造に関するデザインパターンです。
本物のオブジェクト(Real Subject)への参照を持つ代理オブジェクト(Proxy)を間に挟むことで、 アクセス制御・遅延初期化・ログ記録・キャッシュなどを本物のオブジェクトを変更せずに実現できます。
ゲーム開発では、重いアセット(テクスチャ・音声ファイル)の遅延ロードに活用できます。 「アセットが実際に必要になるまでロードしない」という最適化を、クライアント側のコードを変えずに実現できます。
構成
classDiagram
class ISubject {
<< interface >>
+ Request()
}
class RealSubject {
+ Request()
}
class Proxy {
- _realSubject : RealSubject
+ Request()
}
RealSubject ..|> ISubject : implements
Proxy ..|> ISubject : implements
Proxy o-- RealSubject : delegates
Client ..> ISubject : << use >>
| 要素 | 役割 |
|---|---|
| ISubject | RealSubject と Proxy を統一するインターフェース |
| RealSubject | 本物の処理を行うオブジェクト |
| Proxy | RealSubject へのアクセスを制御する代理オブジェクト |
| Client | ISubject 経由で使う(Proxy か RealSubject かを意識しない) |
実装例(C#)
クラス概要
早速実装例です。今回はC#でゲーム開発を行う場合を想定してみました。
利用ケースは以下のように、重いテクスチャを遅延ロードする仮想Proxy(Virtual Proxy)の実装です。
ITexture:テクスチャの共通インターフェース(ISubject)RealTexture:実際にファイルをロードするクラス(RealSubject)TextureProxy:初回アクセス時だけロードする遅延Proxy(Proxy)
ソースコード
1. 共通インターフェース(ISubject)
C#
/// <summary>
/// テクスチャインターフェース (ISubject)
/// </summary>
public interface ITexture
{
string Name { get; }
void Render();
}2. 本物のテクスチャ(RealSubject)
C#
using System;
/// <summary>
/// 実際のテクスチャ (Real Subject)
/// コンストラクタでファイルをロードする(重い処理)
/// </summary>
public class RealTexture : ITexture
{
public string Name { get; }
public RealTexture(string name)
{
Name = name;
// ファイルロードの重い処理をシミュレート
Console.WriteLine($"[RealTexture] '{name}' をディスクからロード中...");
}
public void Render()
{
Console.WriteLine($"[RealTexture] '{Name}' を描画");
}
}3. 遅延ロードProxy(Proxy)
C#
/// <summary>
/// テクスチャの遅延ロードProxy (Proxy)
/// 初回の Render() 呼び出し時にだけ RealTexture を生成する
/// </summary>
public class TextureProxy : ITexture
{
public string Name { get; }
private RealTexture _realTexture; // 遅延初期化
public TextureProxy(string name)
{
Name = name;
// ここではファイルロードしない
Console.WriteLine($"[Proxy] '{name}' のProxyを作成(まだロードしない)");
}
public void Render()
{
// 初回アクセス時だけ本物を生成(遅延ロード)
if (_realTexture == null)
{
_realTexture = new RealTexture(Name);
}
_realTexture.Render();
}
}4. クライアントコード
C#
using System;
class ProxySample
{
static void Main()
{
// Proxy を生成(この時点ではロードしない)
ITexture bgTexture = new TextureProxy("background.png");
ITexture enemySprite = new TextureProxy("enemy_red.png");
Console.WriteLine("\n--- ゲームスタート ---");
// 背景を描画(初回ロードが発生)
bgTexture.Render();
// => [RealTexture] 'background.png' をディスクからロード中...
// => [RealTexture] 'background.png' を描画
// 2回目は既にロード済みのものを使う
bgTexture.Render();
// => [RealTexture] 'background.png' を描画
// enemySprite はこの時点までロードされていない
Console.WriteLine("(enemy_red.png はまだロードされていない)");
enemySprite.Render();
// => [RealTexture] 'enemy_red.png' をディスクからロード中...
// => [RealTexture] 'enemy_red.png' を描画
}
}使いどころ
- 重いオブジェクトを必要になるまでロードしたくないとき(Virtual Proxy)
- オブジェクトへのアクセスを権限チェックで制御したいとき(Protection Proxy)
- アクセスのログ記録やキャッシュを本物のクラスを変えずに追加したいとき(Logging / Caching Proxy)
長所・短所
✅ 長所
- Real Subject を変更せずにアクセス制御・最適化ができる(開放閉鎖の原則)
- 遅延ロードでアプリの起動パフォーマンスを改善できる
- クライアントは Proxy の存在を意識せずに ISubject として使える
⚠️ 短所
- クラスが増えるため、シンプルなケースでは過剰設計になる
- Proxy の追加により、処理フローが間接的になりデバッグしにくくなることがある
他GoFパターンとの比較・関係
Adapter との違い
Adapter はインターフェースを変換します。
Proxy は同じインターフェースを保ちながら、アクセスを制御・補完します。
Decorator との違い
Decorator は機能を動的に追加することが目的です。
Proxy はアクセス制御・遅延ロードなどが目的で、機能は変えません。
| パターン | 目的 |
|---|---|
| Adapter | インターフェース変換 |
| Decorator | 機能追加 |
| Proxy | アクセス制御・遅延・ログ |
まとめ
- Proxy パターンは、本物のオブジェクトへのアクセスを代理オブジェクトで制御する
- Virtual Proxy(遅延ロード)・Protection Proxy(権限制御)・Logging Proxy など用途が多い
- ゲーム開発では重いテクスチャ・音声アセットの遅延ロードに有効
- Adapter は変換、Decorator は機能追加、Proxy はアクセス制御という違いを押さえる
- 同じインターフェースを保つためクライアントは Proxy の存在を意識せずに使える

