- •Лабораторная работа №4 Шаблоны проектирования
- •Теоретические сведения
- •Отношения между классами. На диаграммах классов языка uml
- •Суть паттерна
- •Решение
- •Адаптер объектов
- •Адаптер классов
- •Адаптер классов не нуждается во вложенном объекте, так как он может одновременно наследовать и часть существующего класса, и часть сервиса.
- •Фасад (Facade)
- •Концептуальный пример
- •Program.Cs:
- •Output.Txt: Результат выполнения
- •Изолирует клиентов от компонентов подсистемы Уменьшая тем самым число объектов, с которыми клиентам приходится иметь дело, упрощая работу с подсистемой.
- •Позволяет ослабить связанность между подсистемой и ее клиентами.
- •Фасад не исключает возможности приложениям напрямую обращаться к классам подсистемы, если это необходимо.
- •Заместитель (Proxy)
- •3. Локальный запуск сервиса (удалённый прокси). Когда настоящий сервисный объект находится на удалённом сервере.
- •Концептуальный пример
- •Декоратор (Decorator)
- •// Объект
- •} //Ptr2 выходит из области видимости, но объект не //освобождается, потому что есть ptr, который по-прежнему //ссылается на него } //ptr выходит из области видимости, и объект уничтожается
- •Пример на языке c#
- •Порождающие шаблоны Абстрактная фабрика (Abstract Factory)
- •1. Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы.
- •3. Таким образом, еще раз - предоставляет интерфейс для создания семейств, связанных между собой, или зависимых объектов.
- •Клиент пользуется только интерфейсами, заданными в классах «Абстрактная фабрика» и «Абстрактный продукт».
- •Фабричный метод (Factory Method)
- •Void info() {
- •Void info() {
- •Void info() {
- •Int main()
- •Одиночка (Singleton) Суть паттерна
- •If(!p_instance)
- •Поведенческие шаблоны Стратегия (Strategy)
- •Стратегии построения пути.
- •Структура
- •Концептуальный пример
- •Program.Cs: Пример структуры паттерна
- •Output.Txt: Результат выполнения
- •Void useStrategy(void)
- •Void setStrategy(Strategy* o)
- •Int main(int /*argc*/, char* /*argv*/[])
- •Наблюдатель (Observer) Суть паттерна
- •Решение
- •Структура
- •Шаги реализации
- •Концептуальный пример
- •Program.Cs: Пример структуры паттерна
- •// Random.Next(…) - Метод, возвращает случайное целое число //в указанном диапазоне.
- •Output.Txt: Результат выполнения
- •Использование паттерна Observer
- •Команда (Command)
- •Структура
- •Output.Txt: Результат выполнения
- •Задания для лабораторной работы
3. Локальный запуск сервиса (удалённый прокси). Когда настоящий сервисный объект находится на удалённом сервере.
В этом случае заместитель транслирует запросы клиента в вызовы по сети в протоколе, понятном удалённому сервису.
4. Логирование запросов (логирующий прокси). Когда требуется хранить историю обращений к сервисному объекту.
Заместитель может сохранять историю обращения клиента к сервисному объекту.
5. Кеширование объектов («умная» ссылка). Когда нужно кешировать результаты запросов клиентов и управлять их жизненным циклом.
Заместитель может подсчитывать количество ссылок на сервисный объект, которые были отданы клиенту и остаются активными. Когда все ссылки освобождаются, можно будет освободить и сам сервисный объект (например, закрыть подключение к базе данных).
Кроме того, Заместитель может отслеживать, не менял ли клиент сервисный объект.
Это позволит использовать объекты повторно и экономить ресурсы, особенно если речь идёт о больших прожорливых сервисах.
Синонимы: суррогат (Surrogate)
Подменяет другой объект для контроля доступа к нему, то есть является суррогатом другого объекта.
Заместитель применим во всех случаях, когда возникает необходимость сослаться на объект более изощренно, чем это возможно, если использовать простой указатель.
С помощью этого паттерна при доступе к объекту вводится дополнительный уровень косвенности.
Шаги реализации
Определите интерфейс, который бы сделал заместитель и оригинальный объект взаимозаменяемыми.
Создайте класс заместителя. Он должен содержать ссылку на сервисный объект. Чаще всего, сервисный объект создаётся самим заместителем. В редких случаях заместитель получает готовый сервисный объект через конструктора.
Реализуйте методы заместителя в зависимости от его предназначения. В большинстве случаев, проделав какую-то полезную работу, методы заместителя должны передать запрос сервисному объекту.
Подумайте, не реализовать ли вам ленивую инициализацию сервисного объекта при первом обращении клиента к методам заместителя.
Преимущества и недостатки
Позволяет контролировать сервисный объект незаметно для клиента.
Может работать, даже, если сервисный объект ещё не создан.
Может контролировать жизненный цикл служебного объекта.
Усложняет код программы из-за введения дополнительных классов.
Увеличивает время отклика от сервиса.
Применимость
Вот несколько типичных ситуаций, где заместитель оказывается полезным:
удаленный заместитель предоставляет локального представителя вместо объекта, находящегося в другом адресном пространстве;
виртуальный заместитель создает «тяжелые» объекты по требованию;
защищающий заместитель контролирует доступ к исходному объекту. Такие заместители полезны, когда для разных объектов определены различные права доступа;
“умная” ссылка - это замена обычного указателя. Она позволяет выполнить дополнительные действия при доступе к объекту.
К типичным применениям такой ссылки можно отнести:
подсчет числа ссылок на реальный объект, с тем чтобы занимаемую им память можно было освободить автоматически, когда не останется ни одной ссылки (такие ссылки называют еще «умными» указателями);
загрузку объекта в память при первом обращении к нему;
проверку и установку блокировки на реальный объект при обращении к нему, чтобы никакой другой объект не смог в это время изменить его.
Отношения
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;
}
