🧩 Proxy × Strategy
✅ Intent of the Combination​
- Use the
Proxy
pattern to wrap notification processing with access control or logging - Use the
Strategy
pattern to separate and switch the actual notification method (email, Slack, etc.)
This combination allows you to apply reusable pre/post logic (like logging, authentication, or throttling) via Proxy, while keeping the actual notification logic flexible and interchangeable via Strategy.
✅ Common Use Cases​
- You want a shared notification flow (e.g., logging, tracing) handled by a Proxy, while switching notification logic dynamically
- You need different behaviors across environments (e.g., email in production, mock notifications in development)
- You want to apply cross-cutting control (auth, logging, rate limiting) through a Proxy, while decoupling it from specific strategies
✅ UML Class Diagram​
✅ Code Example​
- TypeScript
- PHP
- Python
interface NotificationStrategy {
send(user: string, message: string): void;
}
class EmailStrategy implements NotificationStrategy {
send(user: string, message: string): void {
console.log(`[Email] To: ${user}, Message: ${message}`);
}
}
class SlackStrategy implements NotificationStrategy {
send(user: string, message: string): void {
console.log(`[Slack] To: ${user}, Message: ${message}`);
}
}
interface Notifier {
notify(user: string, message: string): void;
}
class RealNotifier implements Notifier {
constructor(private strategy: NotificationStrategy) {}
notify(user: string, message: string): void {
this.strategy.send(user, message);
}
}
class NotifierProxy implements Notifier {
constructor(private real: Notifier) {}
notify(user: string, message: string): void {
if (!user.includes("@")) {
console.log("Invalid user. Notification aborted.");
return;
}
console.log("Proxy: Access check passed.");
this.real.notify(user, message);
console.log("Proxy: Notification sent.");
}
}
// Usage
const realNotifier = new RealNotifier(new EmailStrategy());
const proxy = new NotifierProxy(realNotifier);
proxy.notify("taro@example.com", "Disk space warning");
<?php
interface NotificationStrategy {
public function send(string $user, string $message): void;
}
class EmailStrategy implements NotificationStrategy {
public function send(string $user, string $message): void {
echo "[Email] To: {$user}, Message: {$message}\n";
}
}
class SlackStrategy implements NotificationStrategy {
public function send(string $user, string $message): void {
echo "[Slack] To: {$user}, Message: {$message}\n";
}
}
interface Notifier {
public function notify(string $user, string $message): void;
}
class RealNotifier implements Notifier {
private NotificationStrategy $strategy;
public function __construct(NotificationStrategy $strategy) {
$this->strategy = $strategy;
}
public function notify(string $user, string $message): void {
$this->strategy->send($user, $message);
}
}
class NotifierProxy implements Notifier {
private Notifier $real;
public function __construct(Notifier $real) {
$this->real = $real;
}
public function notify(string $user, string $message): void {
if (strpos($user, "@") === false) {
echo "Invalid user. Notification aborted.\n";
return;
}
echo "Proxy: Access check passed.\n";
$this->real->notify($user, $message);
echo "Proxy: Notification sent.\n";
}
}
// Usage
$realNotifier = new RealNotifier(new EmailStrategy());
$proxy = new NotifierProxy($realNotifier);
$proxy->notify("taro@example.com", "Disk space warning");
from abc import ABC, abstractmethod
class NotificationStrategy(ABC):
@abstractmethod
def send(self, user: str, message: str) -> None:
pass
class EmailStrategy(NotificationStrategy):
def send(self, user: str, message: str) -> None:
print(f"[Email] To: {user}, Message: {message}")
class SlackStrategy(NotificationStrategy):
def send(self, user: str, message: str) -> None:
print(f"[Slack] To: {user}, Message: {message}")
class Notifier(ABC):
@abstractmethod
def notify(self, user: str, message: str) -> None:
pass
class RealNotifier(Notifier):
def __init__(self, strategy: NotificationStrategy):
self.strategy = strategy
def notify(self, user: str, message: str) -> None:
self.strategy.send(user, message)
class NotifierProxy(Notifier):
def __init__(self, real: Notifier):
self.real = real
def notify(self, user: str, message: str) -> None:
if "@" not in user:
print("Invalid user. Notification aborted.")
return
print("Proxy: Access check passed.")
self.real.notify(user, message)
print("Proxy: Notification sent.")
# Usage
real_notifier = RealNotifier(EmailStrategy())
proxy = NotifierProxy(real_notifier)
proxy.notify("taro@example.com", "Disk space warning")
✅ Explanation​
NotificationStrategy
defines a shared interface for notification methodsEmailStrategy
andSlackStrategy
implement concrete notification behaviorsRealNotifier
is the actual sender, which uses a strategy injected at constructionNotifierProxy
wrapsRealNotifier
and adds logging or access control before/after forwarding calls
This structure decouples variable logic (strategy) from common control logic (proxy) — resulting in cleaner, reusable, and flexible notification architecture.
✅ Summary​
- Proxy provides centralized control like logging, authentication, or monitoring
- Strategy encapsulates swappable behaviors like email, Slack, or mocks
- By combining both, you achieve flexibility and modularity while maintaining separation of concerns