Найти в Дзене
using Dev

Proxy C#

Оглавление

Прокси предназначен для управления доступом к заданному объекту, перехватывая все вызовы к нему и прозрачно замещая его. Ни интерфейс ни функциональность замещенного компонента, с точки зрения клиента, не изменяются.

Данный шаблон используется если:

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

Таким образом, задача Прокси – упростить и/или оптимизировать взаимодействие с объектом, скрывая несущественные для конкретной задачи подробности реализации. При этом он прозрачен для клиента, поскольку предоставляет тот же интерфейс, что и замещаемый объект.

Реализация шаблона может как порождать экземпляр замещаемого объекта, так и ссылаться на уже существующий. Независимо от этого, Прокси контролирует все взаимодействия с объектом, а в некоторых случаях может управлять его существованием.

В зависимости от цели использования можно выделить следующие типы Прокси:

  1. Удаленный прокси (Remote proxy) – обеспечивает взаимодействие с объектом в другом адресном пространстве. Это может быть как другое приложение на текущем компьютере, так и компонент на интернет сервере. При этом клиент обращается к объекту как к локальному, не замечая различий.
  2. Виртуальный прокси (Virtual proxy) – выполняет оптимизацию доступа к объекту, может самостоятельно обрабатывать некоторые запросы. Например, создание ресурсоёмких объектов только при абсолютной необходимости в них. Другим характерным примером может служить кэширование, в результате которого Прокси сам может отвечать на часть запросов.
  3. Защищающий прокси (Protection proxy) – управляет объектом, разграничивая права доступа различных клиентов.
  4. Умная ссылка (Smart reference) – обеспечивает выполнение дополнительных действий при вызове методов объекта. Примерами могут служить подсчет ссылок или обеспечение потокобезопасности работы с объектом.

Разрабатываемый для конкретной задачи Прокси, может сочетать в себе несколько типов. Например Прокси, обеспечивающий доступ к компоненту на сервере (удаленный), кэширующий часть запросов к нему (виртуальный), блокирующий некоторые методы для разных типов клиентов (защищающий) и учитывающий их число (умная ссылка).

Особенности использования

Хорошей практикой порождения экземпляра Прокси является использование Фабричного метода или Абстрактной фабрики. Клиент в этом случае не знает с какой реализацией интерфейса он работает: с реальным объектом или с Прокси. Это обеспечивает больший уровень прозрачности применения шаблона.

Стоит отметить, что шаблон позволяет использовать интерфейс для взаимодействия с замещаемым объектом. В этом случае конкретная реализация скрыта от Прокси и он может работать практически со всеми объектами, поддерживающими данный интерфейс.

Шаблон не накладывает ограничения на вложения одного Прокси в другой. Такой подход позволяет строить их различные конфигурации в процессе работы программы.

Интересный вариант применения шаблона – копирование по требованию. Его идея заключается в следующем: копирование тяжелых объектов всегда ресурсоемкая операция. Но иногда копия на протяжении части или даже всего своего существования не отличается от оригинала. В этом случае можно отложить реальное копирование данных до момента первой модификации копии или оригинала. Это может сэкономить ресурсы при использовании больших объектов.

Реализация шаблона в общем виде

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

Пример реализации

Рассмотрим реализацию на примере имитации работы web браузера.

Создадим интерфейс ISite.

-2

Реализуем данный интерфейс в классе Site.

-3

Так же реализуем интерфейс ISite в классе SiteProxy.

-4

Посмотрим применение.

-5
-6