- Шаблон Proxy (шаблон проектирования)
-
Шаблон Proxy (Заместитель) — Шаблон проектирования. Предоставляет объект, контролирующий доступ, перехватывая все вызовы к нему.
Содержание
Цель
Проблема
Необходимо управлять доступом к объекту, так чтобы создавать громоздкие объекты «по требованию».
Решение
Создать суррогат громоздкого объекта. «Заместитель» хранит ссылку, которая позволяет заместителю обратиться к реальному субъекту (объект класса «Заместитель» может обращаться к объекту класса «Субъект», если интерфейсы «Реального Субъекта» и «Субъекта» одинаковы). Поскольку интерфейс «Реального Субъекта» идентичен интерфейсу «Субъекта», так, что «Заместителя» можно подставить вместо «Реального Субъекта», контролирует доступ к «Реальному Субъекту», может отвечать за создание или удаление «Реального Субъекта». «Субъект» определяет общий для «Реального Субъекта» и «Заместителя» интерфейс, так, что «Заместитель» может быть использован везде, где ожидается «Реальный Субъект». При необходимости запросы могут быть переадресованы «Заместителем» «Реальному Субъекту».
Шаблон proxy бывает нескольких видов, а именно:
- Удаленный: обеспечивает связь с «Субъектом» который находится в другом адресном пространстве или на удалённой машине. Так же может отвечать за кодирование запроса и его аргументов и отправку закодированного запроса реальному «Субъекту»,
- Виртуальный: Обеспечивает создание реального «Субъекта» только тогда, когда он действительно понадобится. Так же может кэшировать часть информации о реальном «Субъекте», чтобы отложить его создание,
- Копировать-при-записи:: Обеспечивает копирование «субъекта» при выполнении клиентом определённых действий. Частный случай «виртуального прокси»
- Защищающий: может проверять, имеет ли вызывающий объект необходимые для выполнения запроса права.
- Кеширующий прокси: Обеспечивает временное хранение результатов расчёта до отдачи множественным клиентам, которые могут разделить эти результаты.
- Экранирующий прокси: Защищает «Субъект» от опасных клиентов (или наоборот).
- Синхронизирующий прокси: Производит синхронизированный контроль доступа к «Субъекту» в асинхронной многопоточной среде.
- Smart reference proxy: Производит дополнительные действиия когда на «Субъект» создается ссылка, например рассчитывает количество активных ссылок на «Субъект».
Плюсы
- удаленный заместитель;
- виртуальный заместитель может выполнять оптимизацию;
- защищающий заместитель;
- "умная" ссылка;
Минусы
- резкое увеличение времени отклика.
Применимость
Шаблон Proxy может применяться в таких случаях работы с сетевым соединением, огромным объектом в памяти (или на диске) или любым другим ресурсом который сложно или тяжело копировать. Хорошо известный пример применения — объект подсчитывающий число ссылок.
Примеры
public class Main { public static void main(String[] args) { // Create math proxy MathProxy p = new MathProxy(); // Do the math System.out.println("4 + 2 = " + p.add(4, 2)); System.out.println("4 - 2 = " + p.sub(4, 2)); System.out.println("4 * 2 = " + p.mul(4, 2)); System.out.println("4 / 2 = " + p.div(4, 2)); } } /** * "Subject" */ public interface IMath { public double add(double x, double y); public double sub(double x, double y); public double mul(double x, double y); public double div(double x, double y); } /** * "Real Subject" */ public class Math implements IMath { public double add(double x, double y) { return x + y; } public double sub(double x, double y) { return x - y; } public double mul(double x, double y) { return x * y; } public double div(double x, double y) { return x / y; } } /** * "Proxy Object" */ public class MathProxy implements IMath { private Math math; public MathProxy() { math = new Math(); } public double add(double x, double y) { return math.add(x, y); } public double sub(double x, double y) { return math.sub(x, y); } public double mul(double x, double y) { return math.mul(x, y); } public double div(double x, double y) { return math.div(x, y); } }
C++
/** * "Subject" */ class IMath { public: virtual double add(double x, double y) = 0; virtual double sub(double x, double y) = 0; virtual double mul(double x, double y) = 0; virtual double div(double x, double y) = 0; }; /** * "Real Subject" */ class Math : public IMath { public: double add(double x, double y) { return x + y; } double sub(double x, double y) { return x - y; } double mul(double x, double y) { return x * y; } double div(double x, double y) { return x / y; } }; /** * "Proxy Object" */ class MathProxy : public IMath { public: double add(double x, double y) { return math.add(x, y); } double sub(double x, double y) { return math.sub(x, y); } double mul(double x, double y) { return math.mul(x, y); } double div(double x, double y) { return math.div(x, y); } private: Math math; }; #include <iostream> using std::cout; using std::endl; int main() { // Create math proxy MathProxy p; // Do the math cout << "4 + 2 = " << p.add(4, 2) << endl; cout << "4 - 2 = " << p.sub(4, 2) << endl; cout << "4 * 2 = " << p.mul(4, 2) << endl; cout << "4 / 2 = " << p.div(4, 2) << endl; return 0; }
C#
class MainApp { static void Main() { // Create math proxy MathProxy p = new MathProxy(); // Do the math Console.WriteLine("4 + 2 = " + p.Add(4, 2)); Console.WriteLine("4 - 2 = " + p.Sub(4, 2)); Console.WriteLine("4 * 2 = " + p.Mul(4, 2)); Console.WriteLine("4 / 2 = " + p.Div(4, 2)); // Wait for user Console.Read(); } } // "Subject" public interface IMath { double Add(double x, double y); double Sub(double x, double y); double Mul(double x, double y); double Div(double x, double y); } // "RealSubject" class Math : IMath { public double Add(double x, double y){return x + y;} public double Sub(double x, double y){return x - y;} public double Mul(double x, double y){return x * y;} public double Div(double x, double y){return x / y;} } // "Proxy Object" class MathProxy : IMath { Math math; public MathProxy() { math = new Math(); } public double Add(double x, double y) { return math.Add(x,y); } public double Sub(double x, double y) { return math.Sub(x,y); } public double Mul(double x, double y) { return math.Mul(x,y); } public double Div(double x, double y) { return math.Div(x,y); } }