Proxy
Паттерн-заместитель: объект-прокси стоит перед настоящим объектом и контролирует доступ к нему.
Proxy подставляет вместо реального объекта заместитель с тем же интерфейсом, чтобы управлять доступом к нему: отложить создание, кешировать, проверять права, логировать.
Какую задачу решает
Реальный объект может быть дорогим (тяжёлая загрузка), требовать проверки прав или удалённым. Прокси имеет тот же интерфейс, поэтому клиент не замечает подмены, но между ним и объектом появляется управляемая прослойка. Виды: виртуальный (ленивая загрузка), кеширующий, защитный (доступ), удалённый.
Идея и реализация
Пример виртуального + кеширующего прокси: реальный «сервис» дорого считает результат, прокси откладывает работу и кеширует ответы.
class Database: # дорогой реальный объект
def query(self, key):
print(f"[БД] тяжёлый запрос: {key}")
return key.upper()
class CachingProxy: # тот же интерфейс query()
def __init__(self):
self._db = None
self._cache = {}
def query(self, key):
if self._db is None: # ленивое создание
print("[proxy] создаю соединение")
self._db = Database()
if key not in self._cache: # кеширование
self._cache[key] = self._db.query(key)
else:
print(f"[proxy] из кеша: {key}")
return self._cache[key]
proxy = CachingProxy()
print(proxy.query("user"))
print(proxy.query("user"))
Вывод:
[proxy] создаю соединение [БД] тяжёлый запрос: user USER [proxy] из кеша: user USER
Первый вызов создаёт соединение и идёт в «БД». Второй вызов того же ключа отвечает из кеша — тяжёлый запрос не повторяется. Клиент вызывает query одинаково; вся логика спрятана в прокси.
Заметьте, что прокси решил здесь сразу две задачи: отложил дорогое создание соединения до первого реального запроса (виртуальный прокси) и закешировал ответы (кеширующий прокси). На практике один прокси часто совмещает несколько ролей. Главное, что объединяет все виды, — единый с реальным объектом интерфейс: клиент не должен догадываться, общается он напрямую или через заместителя. Стоит прокси нарушить контракт (например, вернуть не то при промахе кеша) — и абстракция течёт.
Самый показательный пример — защитный прокси. Реальный объект умеет всё, а прокси перед каждым вызовом проверяет права текущего пользователя и либо пропускает запрос, либо бросает исключение. Бизнес-логика реального объекта остаётся чистой и ничего не знает об авторизации — эта забота вынесена в отдельный слой, который легко включить, выключить или протестировать независимо.
Proxy против Decorator
Структурно они близки (обёртка с тем же интерфейсом), но цель разная: Decorator добавляет поведение, а Proxy контролирует доступ к объекту, обычно управляя его жизненным циклом.
Где встречается
ORM с ленивой загрузкой связей, кеширующие обёртки (functools.lru_cache — идейно прокси над функцией), защита доступа в API-шлюзах, удалённые прокси (gRPC/REST-клиенты), виртуальные изображения в редакторах.
Итог
- Proxy — заместитель с тем же интерфейсом, что и реальный объект.
- Виды: виртуальный, кеширующий, защитный, удалённый.
- В отличие от Decorator, цель — контроль доступа, а не добавление поведения.