Шаблон Proxy (определяет объект-заместитель англ. surrogate иначе -заменитель англ. placeholder) — шаблон проектирования, который предоставляет объект, который контролирует доступ к другому объекту, перехватывая все вызовы (выполняет функцию контейнера).
В реальной жизни можно привести следующий пример: сотрудникам одного из подразделений фирмы регулярно требуется получать информацию о том, какого числа бухгалтерия планирует выплатить зарплату. С одной стороны каждый из них может индивидуально и регулярно ездить в бухгалтерию для выяснения этого вопроса (полагаю такая ситуация не редка во многих организациях). С другой стороны, при приближении планируемой даты подразделение может выбрать одного человека, который будет выяснять эту информацию у бухгалтерии, а в последствии уже все в подразделении могут выяснить эту информацию у него (что значительно быстрее). Вот именно этот человек и будет реализованным «прокси» паттерном, который будет предоставлять специальный механизм доступа к информации из бухгалтерии.
Проблема
Необходимо управлять доступом к объекту так, чтобы создавать громоздкие объекты «по требованию».
Решение
Создать суррогат громоздкого объекта. «Заместитель» хранит ссылку, которая позволяет заместителю обратиться к реальному субъекту (объект класса «Заместитель» может обращаться к объекту класса «Субъект», если интерфейсы «Реального Субъекта» и «Субъекта» одинаковы). Поскольку интерфейс «Реального Субъекта» идентичен интерфейсу «Субъекта», так, что «Заместителя» можно подставить вместо «Реального Субъекта», контролирует доступ к «Реальному Субъекту», может отвечать за создание или удаление «Реального Субъекта». «Субъект» определяет общий для «Реального Субъекта» и «Заместителя» интерфейс, так, что «Заместитель» может быть использован везде, где ожидается «Реальный Субъект». При необходимости запросы могут быть переадресованы «Заместителем» «Реальному Субъекту».
Шаблон proxy бывает нескольких видов, а именно:
- Удаленный заместитель (англ. remote proxies) : обеспечивает связь с «Субъектом», который находится в другом адресном пространстве или на удалённой машине. Так же может отвечать за кодирование запроса и его аргументов и отправку закодированного запроса реальному «Субъекту»,
- Виртуальный заместитель (англ. virtual proxies): обеспечивает создание реального «Субъекта» только тогда, когда он действительно понадобится. Так же может кэшировать часть информации о реальном «Субъекте», чтобы отложить его создание,
- Копировать-при-записи: обеспечивает копирование «субъекта» при выполнении клиентом определённых действий (частный случай «виртуального прокси»).
- Защищающий заместитель (англ. protection proxies): может проверять, имеет ли вызывающий объект необходимые для выполнения запроса права.
- Кэширующий прокси: обеспечивает временное хранение результатов расчёта до отдачи их множественным клиентам, которые могут разделить эти результаты.
- Экранирующий прокси: защищает «Субъект» от опасных клиентов (или наоборот).
- Синхронизирующий прокси: производит синхронизированный контроль доступа к «Субъекту» в асинхронной многопоточной среде.
- Smart reference proxy: производит дополнительные действия, когда на «Субъект» создается ссылка, например, рассчитывает количество активных ссылок на «Субъект».
Преимущества и недостатки от применения
Преимущества:
- удаленный заместитель;
- виртуальный заместитель может выполнять оптимизацию;
- защищающий заместитель;
- «умная» ссылка;
- Недостатки
- резкое увеличение времени отклика.
Сфера применения
Шаблон Proxy может применяться в случаях работы с сетевым соединением, с огромным объектом в памяти (или на диске) или с любым другим ресурсом, который сложно или тяжело копировать. Хорошо известный пример применения — объект, подсчитывающий число ссылок.
Пример реализации на ABAP:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | " Определяет общий для реального объекта и прокси объекта интерфейс INTERFACE lif_math.    METHODS:       ADD IMPORTING X TYPE F                     y TYPE F           RETURNING VALUE(Z) TYPE F,       sub IMPORTING X TYPE F                     y TYPE F           RETURNING VALUE(Z) TYPE F,       mul IMPORTING X TYPE F                     y TYPE F           RETURNING VALUE(Z) TYPE F,       DIV IMPORTING X TYPE F                     y TYPE F           RETURNING VALUE(Z) TYPE F. ENDINTERFACE. " Определение реального объекта CLASS math DEFINITION.   PUBLIC SECTION.     INTERFACES: lif_math.     ALIASES:       mul FOR lif_math~mul,       sub FOR lif_math~sub,       ADD FOR lif_math~ADD,       DIV FOR lif_math~DIV. ENDCLASS. CLASS math IMPLEMENTATION.   METHOD lif_math~ADD.     Z = X + y.   ENDMETHOD.   METHOD lif_math~sub.     Z = X - y.   ENDMETHOD.   METHOD lif_math~mul.     Z = X * y.   ENDMETHOD.   METHOD lif_math~DIV.     Z = X / y.   ENDMETHOD. ENDCLASS. " Прокси (заместитель), хранит ссылку которая позволяет  " обратиться к реальному субъекту, Так как оба класса  " имеют один интерфейс, прокси может всегда быть использован  " вместо реального субъекта. CLASS proxy DEFINITION.   PUBLIC SECTION.     INTERFACES: lif_math.     METHODS:       CONSTRUCTOR.   PRIVATE SECTION.     DATA: go_math TYPE REF TO math. ENDCLASS. CLASS proxy IMPLEMENTATION.   METHOD CONSTRUCTOR.     CREATE OBJECT go_math.   ENDMETHOD.   " Быстрые операции не требуют обращения к реальному субъекту   METHOD lif_math~ADD.     Z = X + y.   ENDMETHOD.   METHOD lif_math~sub.     Z = X - y.   ENDMETHOD.   " Медленные операции требуют обращения к субъекту   METHOD lif_math~mul.     Z = go_math->mul( X = X y = y ).   ENDMETHOD.   METHOD lif_math~DIV.     Z = go_math->div( X = X y = y ).   ENDMETHOD. ENDCLASS. | 
