Что это такое
Паттерн Заместитель (Proxy) ставит перед реальным объектом замену с тем же интерфейсом. Вызывающий код обращается к заместителю так, будто это настоящий объект; заместитель сам решает, когда и как привлекать оригинал.
Типичные задачи заместителя: кэширование ответов, проверка доступа, отложенное создание дорогих объектов, подсчёт вызовов.
Пример: кэширующий заместитель
Настоящий сервис погоды работает медленно. Заместитель отвечает на повторные вопросы из своего кэша и обращается к сервису только за новыми — оба класса соответствуют одному и тому же протоколу Weather, поэтому вызывающий код не может их различить.
Замена, которая запоминает
Первый вопрос о Paris доходит до удалённого сервиса; на второй отвечает кэш — строка «обращение к удалённому сервису» выводится только один раз.
Вывод: полная программа на Python
from typing import Protocol
class Weather(Protocol):
def forecast(self, city: str) -> str: ...
# Настоящий сервис медленный и дорогой.
class WeatherService:
def forecast(self, city: str) -> str:
print(" (обращение к удалённому сервису...)")
return "солнечно, город " + city
# Заместитель стоит перед сервисом и кэширует ответы.
class CachedWeather:
def __init__(self) -> None:
self.service = WeatherService()
self.cache: dict[str, str] = {}
def forecast(self, city: str) -> str:
cached = self.cache.get(city)
if cached is not None:
return cached + " (из кэша)"
answer = self.service.forecast(city)
self.cache[city] = answer
return answer
w = CachedWeather()
print(w.forecast("Paris"))
print(w.forecast("Paris"))
Когда использовать
Используйте его, чтобы добавить кэширование, контроль доступа, ленивость или учёт перед тем, что вы не можете или не должны менять, — особенно перед удалёнными или дорогими ресурсами.
Не используйте его, если объект ваш и поведение должно находиться внутри него. Заместитель нужен для управления доступом; декоратор — для добавления поведения слоями. Выбирайте то, что соответствует цели.
Плюсы и минусы
Плюсы: вызывающий код вообще не нужно менять; дорогая работа пропускается или контролируется в одном месте.
Минусы: скрытое поведение — вызывающий код может получить ответ из кэша, не зная об этом; устаревший кэш и неожиданные отказы приходится отлаживать за невинно выглядящим интерфейсом.