Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лабы / Лабораторная_работа_по_паттернам_new_—_копия.docx
Скачиваний:
0
Добавлен:
11.02.2026
Размер:
1.18 Mб
Скачать

3. Локальный запуск сервиса (удалённый прокси). Когда настоящий сервисный объект находится на удалённом сервере.

 В этом случае заместитель транслирует запросы клиента в вызовы по сети в протоколе, понятном удалённому сервису.

 4. Логирование запросов (логирующий прокси). Когда требуется хранить историю обращений к сервисному объекту.

 Заместитель может сохранять историю обращения клиента к сервисному объекту.

5. Кеширование объектов («умная» ссылка). Когда нужно кешировать результаты запросов клиентов и управлять их жизненным циклом.

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

Кроме того, Заместитель может отслеживать, не менял ли клиент сервисный объект.

Это позволит использовать объекты повторно и экономить ресурсы, особенно если речь идёт о больших прожорливых сервисах.

Синонимы: суррогат (Surrogate)

Подменяет другой объект для контроля доступа к нему, то есть является суррогатом другого объекта.

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

С помощью этого паттерна при доступе к объекту вводится дополнительный уровень косвенности.

Шаги реализации

  1. Определите интерфейс, который бы сделал заместитель и оригинальный объект взаимозаменяемыми.

  2. Создайте класс заместителя. Он должен содержать ссылку на сервисный объект. Чаще всего, сервисный объект создаётся самим заместителем. В редких случаях заместитель получает готовый сервисный объект через конструктора.

  3. Реализуйте методы заместителя в зависимости от его предназначения. В большинстве случаев, проделав какую-то полезную работу, методы заместителя должны передать запрос сервисному объекту.

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

Преимущества и недостатки

  •  Позволяет контролировать сервисный объект незаметно для клиента.

  •  Может работать, даже, если сервисный объект ещё не создан.

  •  Может контролировать жизненный цикл служебного объекта.

  •  Усложняет код программы из-за введения дополнительных классов.

  •  Увеличивает время отклика от сервиса.

 

Применимость

Вот несколько типичных ситуаций, где заместитель оказывается полезным:

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

  • виртуальный заместитель создает «тяжелые» объекты по требованию;

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

  • умная” ссылка - это замена обычного указателя. Она позволяет выполнить дополнительные действия при доступе к объекту.

  • К типичным применениям такой ссылки можно отнести:

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

    • загрузку объекта в память при первом обращении к нему;

    • проверку и установку блокировки на реальный объект при обращении к нему, чтобы никакой другой объект не смог в это время изменить его.

Отношения

Proxy при необходимости переадресует запросы объекту RealSubject.

Детали зависят от вида заместителя.

Родственные паттерны

Паттерн адаптер предоставляет другой интерфейс к адаптируемому объекту.

!!!Напротив, заместитель в точности повторяет интерфейс своего субъекта!

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

Несколько замечаний относительно Декоратора. Хотя его реализация и похожа на реализацию заместителя, но назначение совершенно иное.

!!!Декоратор добавляет объекту новые обязанности, а заместитель контролирует доступ к объекту.

Заместитель (Proxy) замещает другой объект для обеспечения контроля доступа к нему.

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

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

Проблема: необходимо управлять доступом к объекту так, чтобы не создавать громоздкие объекты «по требованию».

Решение: создать суррогат громоздкого объекта. «Заместитель» хранит ссылку, которая позволяет заместителю обратиться к реальному субъекту.

Объект класса «Заместитель» может обращаться к объекту класса «Субъект», если интерфейсы «Реального Субъекта» и «Субъекта» одинаковы.

Поскольку интерфейс «Реального Субъекта» идентичен интерфейсу «Субъекта», «Заместителя» можно подставить вместо «Реального Субъекта».

«Заместитель» контролирует доступ к «Реальному Субъекту», может отвечать за создание или удаление «Реального Субъекта».

«Субъект» определяет общий для «Реального Субъекта» и «Заместителя» интерфейс. Так, что «Заместитель» может быть использован везде, где ожидается «Реальный Субъект».

При необходимости запросы могут быть переадресованы «Заместителем» «Реальному Субъекту».

class IMath

{

public:

virtual double add(double, double) = 0;

virtual double sub(double, double) = 0;

virtual double mul(double, double) = 0;

virtual double div(double, double) = 0;

};

/**

* "Real Subject"

*/

class Math : public IMath

{

public:

virtual double add(double x, double y)

{

return x + y;

}

virtual double sub(double x, double y)

{

return x - y;

}

virtual double mul(double x, double y)

{

return x * y;

}

virtual double div(double x, double y)

{

return x / y;

}

};

/**

* "Proxy Object"

*/

class MathProxy : public IMath

{

public:

MathProxy()

{

math = new Math();

}

virtual ~MathProxy()

{

delete math;

}

virtual double add(double x, double y)

{

return math->add(x, y);

}

virtual double sub(double x, double y)

{

return math->sub(x, y);

}

virtual double mul(double x, double y)

{

return math->mul(x, y);

}

virtual double div(double x, double y)

{

return math->div(x, y);

}

private:

IMath *math;

};

#include <iostream>

using std::cout;

using std::endl;

int main()

{

// Create math proxy

IMath *proxy = new MathProxy();

// Do the math

cout << "4 + 2 = " << proxy->add(4, 2) << endl;

cout << "4 - 2 = " << proxy->sub(4, 2) << endl;

cout << "4 * 2 = " << proxy->mul(4, 2) << endl;

cout << "4 / 2 = " << proxy->div(4, 2) << endl;

delete proxy;

return 0;

}