Proxy

Назначение

Proxy представляет собой искусственный заменитель какого либо существующего объекта, имеющий с этим объектом общий интерфейс и управляющий доступом к нему. Есть три канонических области применения Porxy:

  • Remote proxy - для управления доступом к удаленному объекту, который может быть расположен на другом сервере или в другой системе
  • Virtual proxy - для управления доступом к объекту, который затартно создавать
  • Protection proxy - для управления доступом к объекту в соответствии с правами доступа.

Описание

Допустим, имеется объект, доступом к которому мы хотим управлять. Контракт взаимодействия с этим объектом должен быть выражен в виде интерфейса, который используют клиенты. Для того чтобы управлять доступом к оригинальному объекту мы создаем новую реализацию его интерфейса, называемую proxy, которая имеет у себя ссылку на исходный объект. Proxy объект управляет доступом к проксируемому объекту, при необходимости, делегируя ему вызовы методов.

Proxy не обязан иметь конструктор с аргументом проксируемого объекта (как это делает Decorator), он может сам создавать и кешировать оригинальный объект.

Возможны сложности с equals.

Реализация

Collaboration diagram

Class diagram

Client
Client
Клиентский код, использует сервис через его интерфейс
Service
BookParser
Интерфейс, который фиксирует контракт взаимодействия с сервисом
ServiceRealImpl
BookParserImpl
Имеющаяся реализация, класс, к объектам которого надо контролировать доступ
ServiceProxy
LazyBookParserProxy
Proxy, который реализует тот же интерфейс, что и реальный сервис и имеет на него ссылку для делегирования вызовов
  • proxy реализует интерфейс проксируемого объекта
  • proxy имеет ссылку на проксируемый объект
  • proxy может не принимать готовый проксируемый объект, а создавать его в нужный момент из параметров, которые он получил в конструкторе.

Примеры

Допустим, существует класс BookParser для обработки книг из текстового вида. Результатом обработки является различные метаданные, полученные в процессе: число страниц, число слов и т.д. Обработка больших книг занимает много времени, которое не всегда необходимо. Для того чтобы отложить трудоемкую операцию до тех пор, пока она не станет гарантировано нужна, можно использовать proxy. Proxy объект сохраняет в себе исходное строковое представление книги, но не инициализирует BookParser до тех пор, пока без него нельзя будет обойтись. Как только происходит вызов метода, непременно требующий обработки книги, происходит инициализация BookParser и его кеширование в proxy объекте для того чтобы быстро отвечать на повторные/новые вызовы.

Варианты

  • три основных вида в зависимости от задачи
  • конструктор принимает готовый объект, реализующий Service - proxy не отвечает сам за создание объекта
  • конструктор принимает параметры, из которых в нужный момент можно будет сделать Service

Чем отличается

Adapter – Proxy не изменяет интерфейс объекта (proxy имеет тот же интерфейс, заменителем которого он является), в то время как назначение Adapter как раз в том, чтобы изменить интерфейс таким образом, чтобы он подошел в нужном месте.

Decorator структурно соответствует случаю Proxy, который принимает в конструкторе готовый объект, но отличается от Proxy намерением: Decorator добавляет какой-либо новый функционал или модифицирует существующий, а Proxy предназначен для контроля доступа. Для Decorator типична ситуация, когда Decorator обернут один в другой как луковична кожура, для Proxy, хоть это и возможно, но не типично: редко на одном объекте используется больше одно Proxy.

Ссылки

https://java-design-patterns.com/patterns/proxy/

https://github.com/iluwatar/java-design-patterns/tree/master/proxy

https://refactoring.guru/design-patterns/proxy

Proxy Pattern – Design Patterns (ep 10)

Structural Patterns (comparison) – Design Patterns (ep 12)

Baeldung- The Proxy Pattern in Java