НЕ МОЛЧИ!!!    Сделай что-нибудь,
чтобы остановить войну России в Украине.
...бойтесь людей равнодушных - именно с их молчаливого согласия происходят все самые ужасные преступления на свете.   ("Репортаж с петлёй на шее")

Шаблон проектирования Proxy (Прокси)

Рассматривается структурный шаблон проектирования Proxy, приведено описание шаблона и пример реализации на PHP.

Содержание

  • Применение
  • Структура шаблона
  • Реализация
  • Итоги

У этого шаблона несколько имен: Proxy, Прокси, Заместитель.
Шаблон проектирования Proxy очень похож на рассмотренный ранее структурный шаблон проектирования Декоратор. Но если последний используют, чтобы расширить функции заменяемого класса, то у нашего другие задачи.

Применение

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

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

И это, конечно, только некоторые возможности данного шаблона. Они определяются задачами проектирования и ограничены лишь вашей фантазией.

Структура шаблона

В приводимом примере с помощью шаблона Proxy будем уменьшать нагрузку на сервер. В примере будут использоваться такие структуры.

  • IMath — интерфейс, определяющий функционал сервера.
  • Math — класс основного объекта, производящего вычисления, реализует интерфейс IMath.
  • MathProxy — класс прокси объекта, также реализует интерфейс IMath.

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

Реализация

Итак, вначале определяем интерфейс нашего вычислителя.


interface IMath
{
public function add($operand1, $operand2);

public function subj($operand1, $operand2);

public function mul($operand1, $operand2);

public function div($operand1, $operand2);

}

Теперь определим основной вычислитель.


class Math implements IMath
{
    public function add($oper1, $oper2)
    {
        return $oper1 + $oper2;
    }

    public function subj($oper1, $oper2)
    {
        return $oper1 - $oper2;
    }

    public function mul($oper1, $oper2)
    {
        return $oper1 * $oper2;
    }

    public function div($oper1, $oper2)
    {
        return $oper1 / $oper2;
    }
}

Наш прокси-объект, будет выполнять операции сложения и вычитания самостоятельно, а умножение и деление переадресовать подменяемому объекту.

class MathProxy implements IMath
{
    protected $math = null;

    public function add($oper1, $oper2)
    {
        return $oper1 + $oper2;
    }

    public function subj($oper1, $oper2)
    {
        return $oper1 - $oper2;
    }

    public function mul($oper1, $oper2)
    {
        if ($this->math === null) {
            $this->math = new Math();
        } 
        return $this->math->mul($oper1, $oper2);
    }

    public function div($oper1, $oper2)
    {
        if ($this->math === null) {
            $this->math = new Math();
        } 
        return $this->math->div($oper1, $oper2);
    }
}

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

Итоги

Итак, вы познакомились с шаблоном проектирования Proxy, выполняющим роль посредника между клиентом и основным объектом запроса. Такое взаимодействие имеет массу возможностей, вот лишь некоторые из них.

  • Снижение нагрузки на основной объект за счет выполнения части его функций.
  • Управление доступом к основному объекту.
  • Ленивая инициализация основного объекта, когда ресурсоёмкий объект создается лишь в случае его необходимости.

Как вы понимаете, этот список можно еще долго дополнять.

К недостаткам следует отнести некоторое усложнение кода и в некоторых случаях дополнительная задержка ответа, когда исполнение запроса транслируется основному объекту.

Перейти к списку шаблонов проектирования.