Паттерн Proxy (заместитель)
В этой теме мы разберем:
- суть паттерна;
- структуру его работы;
- применимость и шаги реализации паттерна;
- его отношения с другими паттернами.
Суть паттерна
Proxy (заместитель) — это структурный паттерн проектирования, который позволяет подставлять вместо реальных объектов специальные объекты-заменители. Эти объекты перехватывают вызовы к оригинальным объектам, позволяя сделать что-то до (или после) передачи им вызова.
Проблема
Для чего вообще необходимо контролировать доступ к объектам? Рассмотрим такой пример: у нас есть внешний ресурсоёмкий объект, который бывает нужен не все время, а только изредка.
Запросы к базе данных могут быть очень медленными
Мы могли бы создавать этот объект не в самом начале программы, а только тогда, когда он кому-то реально понадобится. Каждый клиент объекта получал бы некий код отложенной инициализации. Но, вероятно, это привело бы к множественному дублированию кода.
В идеале код хотелось бы поместить прямо в служебный класс, но это не всегда возможно (он может находиться, например, в закрытой сторонней библиотеке).
Решение
Паттерн Proxy предлагает создать новый класс-дублёр, имеющий тот же интерфейс, что и оригинальный служебный объект. При получении запроса от клиента объект-заместитель сам будет создавать экземпляр служебного объекта и переадресовывать ему всю реальную работу.
Заместитель «притворяется» базой данных, ускоряя работу за счёт ленивой инициализации и кеширования повторяющихся запросов
В чём же здесь польза? Мы можем поместить в класс заместителя какую-то промежуточную логику, которая будет выполняться до (или после) вызовов этих же методов в настоящем объекте. А благодаря одинаковому интерфейсу объект-заместитель можно передать в любой код, ожидающий сервисный объект.
Аналогия из жизни
Платёжной картой можно расплачиваться также, как и наличными.
Платёжная карточка — это заместитель пачки наличных. И карточка, и наличные имеют общий интерфейс — ими можно оплачивать товары. Но преимущество карточки в том, что покупателю теперь не надо таскать с собой тонны наличных, а владельцу магазина не нужно делать дорогостоящую инкассацию наличности в банк — деньги поступают к нему на счёт напрямую.