🧩 Proxy Pattern
✅ Intent
- Indirectly access a real object (Real Subject) by introducing a proxy that performs control, checks, or lazy loading
- The client accesses the proxy instead of the real object, enabling a transparent layer of control or enhancement
- Use cases include access control, caching, logging, lazy loading, and remote calls
✅ Motivation
- You want to delay instantiation of a heavy object (e.g., remote service, image loader, large dataset)
- You need a unified way to enforce access control, logging, or pre-processing
- You want to wrap the real subject without modifying it, following the Open/Closed Principle
- You want to insert a control layer between the client and the real subject
✅ When to Use
- You need lazy initialization of heavyweight objects
- You want to add pre/post-processing around real object access
- You want to hide or abstract away remote boundaries (e.g., RPC, REST API)
- You need transparent logging, monitoring, or caching layers
- You want to mock or replace the real object for testing purposes
✅ Code Example
- TypeScript
- PHP
- Python
// インターフェース
interface Printer {
print(text: string): void;
}
// 実際の処理を行うクラス(本体)
class RealPrinter implements Printer {
print(text: string): void {
console.log(`印刷中: ${text}`);
}
}
// Proxy(アクセスを仲介)
class PrinterProxy implements Printer {
private real: RealPrinter;
constructor() {
this.real = new RealPrinter();
}
print(text: string): void {
console.log("ログ: 印刷を開始します");
this.real.print(text);
console.log("ログ: 印刷が完了しました");
}
}
// 利用例
const printer: Printer = new PrinterProxy();
printer.print("月次レポート");
<?php
interface Printer {
public function print(string $text): void;
}
class RealPrinter implements Printer {
public function print(string $text): void {
echo "印刷中: {$text}\n";
}
}
class PrinterProxy implements Printer {
private RealPrinter $real;
public function __construct() {
$this->real = new RealPrinter();
}
public function print(string $text): void {
echo "ログ: 印刷を開始します\n";
$this->real->print($text);
echo "ログ: 印刷が完了しました\n";
}
}
// 利用例
$printer = new PrinterProxy();
$printer->print("月次レポート");
from abc import ABC, abstractmethod
class Printer(ABC):
@abstractmethod
def print(self, text: str):
pass
class RealPrinter(Printer):
def print(self, text: str):
print(f"印刷中: {text}")
class PrinterProxy(Printer):
def __init__(self):
self._real = RealPrinter()
def print(self, text: str):
print("ログ: 印刷を開始します")
self._real.print(text)
print("ログ: 印刷が完了しました")
# 利用例
printer = PrinterProxy()
printer.print("月次レポート")
✅ Explanation
This code demonstrates the Proxy
pattern, where a PrinterProxy
mediates access to the RealPrinter
.
The Proxy
pattern provides a placeholder object to control access to another object.
It is commonly used for lazy initialization, logging, caching, or access control.
1. Overview of the Proxy Pattern
-
Subject: Common interface used by the client
- Represented by
Printer
- Represented by
-
RealSubject: The actual object that performs the core functionality
- Represented by
RealPrinter
- Represented by
-
Proxy: Controls access to the
RealSubject
and optionally enhances behavior- Represented by
PrinterProxy
- Represented by
-
Client: Uses the
Subject
interface without knowing whether it's dealing with the proxy or real object- For example, calling
printer.print("Monthly Report")
- For example, calling
2. Key Classes and Their Roles
-
Printer
- The common interface (
Subject
) - Defines
print(text: string): void
- The common interface (
-
RealPrinter
- The actual implementation (
RealSubject
) - Implements the
print
method with the real logic
- The actual implementation (
-
PrinterProxy
- The proxy implementation
- Wraps the
RealPrinter
and controls access - Adds logging before and after calling
print
-
Client Code
- Interacts with
PrinterProxy
which delegates toRealPrinter
- Interacts with
3. UML Class Diagram
4. Benefits of the Proxy Pattern
- Access Control: Prevents direct access to the real object, adding a layer of control
- Enhancement: Easily adds cross-cutting concerns like logging, caching, or validation
- Lazy Initialization: Defers creation of the real object until it's needed, saving resources
This pattern is especially useful when you need to intercept or augment access to a real object without modifying it.
It promotes clean layering and improves flexibility, testability, and maintainability.