Proxy (шаблон проектирования)
Шаблон Proxy (Заместитель) — Шаблон проектирования. Предоставляет объект, который контролирует доступ к другому объекту через перехват всех вызовов.
Цель
Проблема
Необходимо управлять доступом к объекту, так чтобы создавать громоздкие объекты «по требованию».
Решение
Создать суррогат громоздкого объекта. «Заместитель» хранит ссылку, которая позволяет заместителю обратиться к реальному субъекту (объект класса «Заместитель» может обращаться к объекту класса «Субъект», если интерфейсы «Реального Субъекта» и «Субъекта» одинаковы). Поскольку интерфейс «Реального Субъекта» идентичен интерфейсу «Субъекта», так, что «Заместителя» можно подставить вместо «Реального Субъекта», контролирует доступ к «Реальному Субъекту», может отвечать за создание или удаление «Реального Субъекта». «Субъект» определяет общий для «Реального Субъекта» и «Заместителя» интерфейс, так, что «Заместитель» может быть использован везде, где ожидается «Реальный Субъект». При необходимости запросы могут быть переадресованы «Заместителем» «Реальному Субъекту».
Диаграмма классов шаблона проектирования Proxy
Шаблон proxy бывает нескольких видов, а именно:
- Удаленный: обеспечивает связь с «Субъектом» который находится в другом адресном пространстве или на удалённой машине. Так же может отвечать за кодирование запроса и его аргументов и отправку закодированного запроса реальному «Субъекту»,
- Виртуальный: Обеспечивает создание реального «Субъекта» только тогда, когда он действительно понадобится. Так же может кэшировать часть информации о реальном «Субъекте», чтобы отложить его создание,
- Копировать-при-записи:: Обеспечивает копирование «субъекта» при выполнении клиентом определённых действий. Частный случай «виртуального прокси»
- Защищающий: может проверять, имеет ли вызывающий объект необходимые для выполнения запроса права.
- Кэширующий прокси: Обеспечивает временное хранение результатов расчёта до отдачи множественным клиентам, которые могут разделить эти результаты.
- Экранирующий прокси: Защищает «Субъект» от опасных клиентов (или наоборот).
- Синхронизирующий прокси: Производит синхронизированный контроль доступа к «Субъекту» в асинхронной многопоточной среде.
- Smart reference proxy: Производит дополнительные действия когда на «Субъект» создается ссылка, например рассчитывает количество активных ссылок на «Субъект».
Плюсы
- удаленный заместитель;
- виртуальный заместитель может выполнять оптимизацию;
- защищающий заместитель;
- "умная" ссылка;
Минусы
- резкое увеличение времени отклика.
Применимость
Шаблон Proxy может применяться в таких случаях работы с сетевым соединением, огромным объектом в памяти (или на диске) или любым другим ресурсом который сложно или тяжело копировать. Хорошо известный пример применения — объект подсчитывающий число ссылок.
Примеры
Java
public class Main {
public static void main(String[] args) {
// Create math proxy
IMath 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#
using System;
using System.Threading;
class MainApp
{
static void Main()
{
// Create math proxy
IMath 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();
}
}
/// <summary>
/// Subject - субъект
/// </summary>
/// <remarks>
/// <li>
/// <lu>определяет общий для <see cref="Math"/> и <see cref="Proxy"/> интерфейс, так что класс
/// <see cref="Proxy"/> можно использовать везде, где ожидается <see cref="Math"/></lu>
/// </li>
/// </remarks>
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);
}
/// <summary>
/// RealSubject - реальный объект
/// </summary>
/// <remarks>
/// <li>
/// <lu>определяет реальный объект, представленный заместителем</lu>
/// </li>
/// </remarks>
class Math : IMath
{
public Math()
{
Console.WriteLine("Create object Math. Wait...");
Thread.Sleep(1000);
}
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;}
}
/// <summary>
/// Proxy - заместитель
/// </summary>
/// <remarks>
/// <li>
/// <lu>хранит ссылку, которая позволяет заместителю обратиться к реальному
/// субъекту. Объект класса <see cref="MathProxy"/> может обращаться к объекту класса
/// <see cref="IMath"/>, если интерфейсы классов <see cref="Math"/> и <see cref="IMath"/> одинаковы;</lu>
/// <lu>предоставляет интерфейс, идентичный интерфейсу <see cref="IMath"/>, так что заместитель
/// всегда может быть предоставлен вместо реального субъекта;</lu>
/// <lu>контролирует доступ к реальному субъекту и может отвечать за его создание
/// и удаление;</lu>
/// <lu>прочие обязанности зависят от вида заместителя:
/// <li>
/// <lu><b>удаленный заместитель</b> отвечает за кодирование запроса и его аргументов
/// и отправление закодированного запроса реальному субъекту в
/// другом адресном пространстве;</lu>
/// <lu><b>виртуальный заместитель</b> может кэшировать дополнительную информацию
/// о реальном субъекте, чтобы отложить его создание.</lu>
/// <lu><b>защищающий заместитель</b> проверяет, имеет ли вызывающий объект
/// необходимые для выполнения запроса права;</lu>
/// </li>
/// </lu>
/// </li>
/// </remarks>
class MathProxy : IMath
{
Math math;
public MathProxy()
{
math = null;
}
/// <summary>
/// Быстрая операция - не требует реального субъекта
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public double Add(double x, double y)
{
return x + y;
}
public double Sub(double x, double y)
{
return x - y;
}
/// <summary>
/// Медленная операция - требует создания реального субъекта
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public double Mul(double x, double y)
{
if (math == null)
math = new Math();
return math.Mul(x, y);
}
public double Div(double x, double y)
{
if (math == null)
math = new Math();
return math.Div(x, y);
}
}
JavaScript
/* Subject */
function IMath() {
this.add = function(x, y) {};
this.sub = function(x, y) {};
}
/* Real Subject */
function RMath() {
/*
IMath.call(this); // агрегируем IMath, т.к. нативного наследования нет
// этот вариант следует использовать вместо прототипирования,
// если в IMath имеются приватные переменные,
// которые могут быть доступны через геттеры в IMath
*/
this.add = function(x, y) {
return x + y;
};
this.sub = function(x, y) {
return x - y;
};
}
RMath.prototype = new IMath();
RMath.prototype.constructor = RMath;
/* Proxy */
function MathProxy() {
var math = new RMath();
this.add = function(x, y) {
return math.add(x, y);
};
this.sub = function(x, y) {
return math.sub(x, y);
};
}
var test = new MathProxy();
alert(test.add(3, 2)); // 5
alert(test.sub(3, 2)); // 1
Object Pascal
См. также
Литература
структурные шаблоны проектирования |
адаптер | мост | компоновщик | декоратор | фасад | заместитель | приспособленец | Выделение частного класса данных |
ar:نمط الوكيل bg:Пълномощно (шаблон) ca:Proxy (patró de disseny) de:Stellvertreter (Entwurfsmuster) en:Proxy pattern es:Proxy (patrón de diseño) fr:Proxy (patron de conception) it:Proxy pattern ja:Proxy パターン lt:Proxy (objektas) pl:Pełnomocnik (wzorzec projektowy) pt:Proxy (padrões de projeto) uk:Замісник (шаблон проектування)
Если вам нравится SbUP.com Сайт, вы можете поддержать его - BTC: bc1qppjcl3c2cyjazy6lepmrv3fh6ke9mxs7zpfky0 , TRC20 и ещё....