Шаблон 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. |