🧩 Proxy パターン
✅ 設計意図
- 元のオブジェクトと同じインターフェースを持つ 代理(Proxy) を介してアクセスを制御
- 認証・キャッシュ・遅延初期化・ログ記録などを中間層で追加
✅ 適用理由
- 実体へのアクセスに前処理や制限を加えたい
- 呼び出し方法を変えずに追加処理を挟みたい
✅ 向いているシーン
- 実処理に対してキャッシュ、認証、トレースなどの制御を行いたい場合
- 外部リソースへのアクセス制御や監視など
✅ コード例
- TypeScript
- PHP
- Python
interface UserProfile {
load(userId: string): object;
}
// 本体
class UserProfileService implements UserProfile {
load(userId: string): object {
console.log(`プロフィール取得: ${userId}`);
return { name: "Hiroshi", id: userId };
}
}
// Proxy(認証と監査を担当)
class UserProfileProxy implements UserProfile {
private real = new UserProfileService();
private auth = new AuthService();
private audit = new AuditService();
load(userId: string): object {
if (!this.auth.authenticate(userId)) {
throw new Error("認証失敗");
}
const profile = this.real.load(userId);
this.audit.log("プロフィール表示");
return profile;
}
}
// 利用例
const proxy = new UserProfileProxy();
const profile = proxy.load("user-123");
console.log(profile);
<?php
interface UserProfile {
public function load(string $userId): array;
}
class UserProfileService implements UserProfile {
public function load(string $userId): array {
echo "プロフィール取得: {$userId}\n";
return ["name" => "Hiroshi", "id" => $userId];
}
}
class UserProfileProxy implements UserProfile {
private UserProfileService $real;
private AuthService $auth;
private AuditService $audit;
public function __construct() {
$this->real = new UserProfileService();
$this->auth = new AuthService();
$this->audit = new AuditService();
}
public function load(string $userId): array {
if (!$this->auth->authenticate($userId)) {
throw new Exception("認証失敗");
}
$profile = $this->real->load($userId);
$this->audit->log("プロフィール表示");
return $profile;
}
}
// 利用例
$proxy = new UserProfileProxy();
$profile = $proxy->load("user-123");
print_r($profile);
from abc import ABC, abstractmethod
class UserProfile(ABC):
@abstractmethod
def load(self, user_id: str) -> dict:
pass
class UserProfileService(UserProfile):
def load(self, user_id: str) -> dict:
print(f"プロフィール取得: {user_id}")
return {"name": "Hiroshi", "id": user_id}
class UserProfileProxy(UserProfile):
def __init__(self):
self._real = UserProfileService()
self._auth = AuthService()
self._audit = AuditService()
def load(self, user_id: str) -> dict:
if not self._auth.authenticate(user_id):
raise Exception("認証失敗")
profile = self._real.load(user_id)
self._audit.log("プロフィール表示")
return profile
# 利用例
proxy = UserProfileProxy()
profile = proxy.load("user-123")
print(profile)
✅ 解説
このコードは Proxy
パターン を使用して、UserProfileService
へのアクセスを UserProfileProxy
が仲介し、
認証や監査といった追加の処理を実現している。
Proxy
パターンは、オブジェクトへのアクセスを制御するための代理を提供するデザインパターンであり、
アクセス制御やログ記録、キャッシュなどに利用される。
1. Proxy パターンの概要
- Subject: クライアントが利用する共通インターフェース
- このコードでは
UserProfile
が該当
- このコードでは
- RealSubject: 実際の処理を行うクラス
- このコードでは
UserProfileService
が該当
- このコードでは
- Proxy:
RealSubject
へのアクセスを制御するクラス- このコードでは
UserProfileProxy
が該当
- このコードでは
- Client:
Subject
を通じてRealSubject
またはProxy
を利用するクラス- このコードでは
proxy.load("user-123")
を呼び出す部分が該当
- このコードでは
2. 主なクラスとその役割
UserProfile
- 共通インターフェース(
Subject
) load(userId: string): object
メソッドを定義
- 共通インターフェース(
UserProfileService
- 実際の処理を行うクラス(
RealSubject
) load
メソッドでユーザープロフィールを取得
- 実際の処理を行うクラス(
UserProfileProxy
Proxy
クラスUserProfileService
をラップし、認証と監査の処理を追加load
メソッドで認証を行い、成功した場合にUserProfileService
の処理を呼び出し、監査ログを記録
AuthService
- 認証処理を行うクラス
AuditService
- 操作の監査ログを記録するクラス
3. UML クラス図
4. Proxy パターンの利点
- アクセス制御: クライアントが直接
UserProfileService
にアクセスするのを防ぎ、認証や監査を追加可能 - 追加機能の付加: 実際の処理の前後にログ出力や認証処理などを追加可能
- 疎結合: クライアントは
UserProfile
インターフェースに依存するため、実装の変更が容易
この設計は、オブジェクトへのアクセスを制御したり、処理の前後に追加の機能を付加する必要がある場面で非常に有効であり、 コードの柔軟性と保守性を向上させる。