Заместитель (шаблон проектирования): различия между версиями
[непроверенная версия] | [непроверенная версия] |
Luver (обсуждение | вклад) Нет описания правки |
|||
Строка 914: | Строка 914: | ||
== Ссылки == |
== Ссылки == |
||
*[http://cpp-reference.ru/patterns/structural-patterns/proxy/ Паттерн Proxy (заместитель)] — назначение, описание, особенности и реализация на С++. |
|||
<references/> |
|||
[[Категория:Шаблоны проектирования]] |
[[Категория:Шаблоны проектирования]] |
Версия от 19:19, 5 января 2012
Заместитель | |
---|---|
Proxy | |
Тип | структурный |
Описан в Design Patterns | Да |
Шаблон Proxy (определяет объект-заместитель англ. surrogate иначе -заменитель англ. placeholder) — шаблон проектирования, который предоставляет объект, который контролирует доступ к другому объекту, перехватывая все вызовы (выполняет функцию контейнера).
Цель
Проблема
Необходимо управлять доступом к объекту так, чтобы создавать громоздкие объекты «по требованию».
Решение
Создать суррогат громоздкого объекта. «Заместитель» хранит ссылку, которая позволяет заместителю обратиться к реальному субъекту (объект класса «Заместитель» может обращаться к объекту класса «Субъект», если интерфейсы «Реального Субъекта» и «Субъекта» одинаковы). Поскольку интерфейс «Реального Субъекта» идентичен интерфейсу «Субъекта», так, что «Заместителя» можно подставить вместо «Реального Субъекта», контролирует доступ к «Реальному Субъекту», может отвечать за создание или удаление «Реального Субъекта». «Субъект» определяет общий для «Реального Субъекта» и «Заместителя» интерфейс, так, что «Заместитель» может быть использован везде, где ожидается «Реальный Субъект». При необходимости запросы могут быть переадресованы «Заместителем» «Реальному Субъекту».
Шаблон proxy бывает нескольких видов, а именно:
- Удаленный заместитель (англ. remote proxies) : обеспечивает связь с «Субъектом», который находится в другом адресном пространстве или на удалённой машине. Так же может отвечать за кодирование запроса и его аргументов и отправку закодированного запроса реальному «Субъекту»,
- Виртуальный заместитель (англ. virtual proxies): обеспечивает создание реального «Субъекта» только тогда, когда он действительно понадобится. Так же может кэшировать часть информации о реальном «Субъекте», чтобы отложить его создание,
- Копировать-при-записи: обеспечивает копирование «субъекта» при выполнении клиентом определённых действий (частный случай «виртуального прокси»).
- Защищающий заместитель (англ. protection proxies): может проверять, имеет ли вызывающий объект необходимые для выполнения запроса права.
- Кэширующий прокси: обеспечивает временное хранение результатов расчёта до отдачи их множественным клиентам, которые могут разделить эти результаты.
- Экранирующий прокси: защищает «Субъект» от опасных клиентов (или наоборот).
- Синхронизирующий прокси: производит синхронизированный контроль доступа к «Субъекту» в асинхронной многопоточной среде.
- Smart reference proxy: производит дополнительные действия, когда на «Субъект» создается ссылка, например, рассчитывает количество активных ссылок на «Субъект».
Преимущества и недостатки от применения
Преимущества:
- удаленный заместитель;
- виртуальный заместитель может выполнять оптимизацию;
- защищающий заместитель;
- "умная" ссылка;
- Недостатки
- резкое увеличение времени отклика.
Сфера применения
Шаблон Proxy может применяться в случаях работы с сетевым соединением, с огромным объектом в памяти (или на диске) или с любым другим ресурсом, который сложно или тяжело копировать. Хорошо известный пример применения — объект, подсчитывающий число ссылок.
Прокси и близкие к нему шаблоны[1]
- Адаптер обеспечивает отличающийся интерфейс к объекту.
- Прокси обеспечивает тот же самый интерфейс.
- Декоратор обеспечивает расширенный интерфейс.
Примеры реализации
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);
}
}
/**
* "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;
}
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);
}
}
/* 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
#
# "Subject" - не нужен
#
#
# "Real Subject"
#
class Math
def add(x, y); x + y; end
def sub(x, y); x - y; end
def mul(x, y); x * y; end
def div(x, y); x / y; end
end
#
# "Proxy Object"
#
class MathProxy
def initialize
@math = Math.new
end
def add(x, y); @math.add(x, y); end
def sub(x, y); @math.sub(x, y); end
def mul(x, y); @math.mul(x, y); end
def div(x, y); @math.div(x, y); end
end
# Create math proxy
p = MathProxy.new;
# Do the math
puts "4 + 2 = #{p.add(4, 2)}"
puts "4 - 2 = #{p.sub(4, 2)}"
puts "4 * 2 = #{p.mul(4, 2)}"
puts "4 / 2 = #{p.div(4, 2)}"
<?php
/// Subject - субъект
/// <lu>определяет общий для Math и "Proxy" интерфейс, так что класс
/// "Proxy" можно использовать везде, где ожидается
interface IMath
{
function Add($x, $y);
function Sub($x, $y);
function Mul($x, $y);
function Div($x, $y);
}
/// RealSubject - реальный объект
/// определяет реальный объект, представленный заместителем
class Math implements IMath
{
public function Math()
{
print ("Create object Math. Wait...");
sleep(5);
}
public function Add($x, $y){return $x + $y;}
public function Sub($x, $y){return $x - $y;}
public function Mul($x, $y){return $x * $y;}
public function Div($x, $y){return $x / $y;}
}
/// Proxy - заместитель
/// хранит ссылку, которая позволяет заместителю обратиться к реальному
/// субъекту. Объект класса "MathProxy" может обращаться к объекту класса
/// "IMath", если интерфейсы классов "Math" и "IMath" одинаковы;
/// предоставляет интерфейс, идентичный интерфейсу "IMath", так что заместитель
/// всегда может быть предоставлен вместо реального субъекта;
/// контролирует доступ к реальному субъекту и может отвечать за его создание
/// и удаление;
/// прочие обязанности зависят от вида заместителя:
/// удаленный заместитель отвечает за кодирование запроса и его аргументов
/// и отправление закодированного запроса реальному субъекту в
/// другом адресном пространстве;
/// виртуальный заместитель может кэшировать дополнительную информацию
/// о реальном субъекте, чтобы отложить его создание.
/// защищающий заместитель проверяет, имеет ли вызывающий объект
/// необходимые для выполнения запроса права;
class MathProxy implements IMath
{
protected $math;
public function __construct()
{
$this->math = null;
}
/// Быстрая операция - не требует реального субъекта
public function Add($x, $y)
{
return $x + $y;
}
public function Sub($x, $y)
{
return $x - $y;
}
/// Медленная операция - требует создания реального субъекта
public function Mul($x, $y)
{
if ($this->math == null)
$this->math = new Math();
return $this->math->Mul($x, $y);
}
public function Div($x, $y)
{
if ($this->math == null)
$this->math = new Math();
return $this->math->Div($x, $y);
}
}
$p = new MathProxy;
// Do the math
print("4 + 2 = ".$p->Add(4, 2));
print("4 - 2 = ".$p->Sub(4, 2));
print("4 * 2 = ".$p->Mul(4, 2));
print("4 / 2 = ".$p->Div(4, 2));
?>
//файл IMath.as
package
{
public interface IMath
{
function add(a : Number, b : Number) : Number;
function sub(a : Number, b : Number) : Number;
function mul(a : Number, b : Number) : Number;
function div(a : Number, b : Number) : Number;
}
}
//файл MathSubject.as
package
{
public class MathSubject implements IMath
{
public function add(a : Number, b : Number) : Number
{
return a + b;
}
public function sub(a : Number, b : Number) : Number
{
return a - b;
}
public function mul(a : Number, b : Number) : Number
{
return a * b;
}
public function div(a : Number, b : Number) : Number
{
return a / b;
}
}
}
//файл MathProxy.as
package
{
public class MathProxy implements IMath
{
private var math : MathSubject;
public function MathProxy()
{
math = new MathSubject();
}
public function add(a : Number, b : Number) : Number
{
return math.add(a, b);
}
public function sub(a : Number, b : Number) : Number
{
return math.sub(a, b);
}
public function mul(a : Number, b : Number) : Number
{
return math.mul(a, b);
}
public function div(a : Number, b : Number) : Number
{
if (b != 0)
return math.div(a, b);
else
{
trace("Division by zero.");
return Number.POSITIVE_INFINITY;
}
}
}
}
//файл Main.as
package
{
import flash.display.Sprite;
public class Main extends Sprite
{
public function Main()
{
playWithMath(new MathSubject());
playWithMath(new MathProxy());
}
public function playWithMath(math : IMath) : void
{
trace(math.add(5, 0));
trace(math.sub(5, 0));
trace(math.mul(5, 0));
trace(math.div(5, 0));
}
}
}
# -*- coding: utf-8 -*-
class IMath:
"""Интерфейс для прокси и реального субъекта"""
def add(self, x, y):
raise NotImplementedError()
def sub(self, x, y):
raise NotImplementedError()
def mul(self, x, y):
raise NotImplementedError()
def div(self, x, y):
raise NotImplementedError()
class Math(IMath):
"""Реальный субъект"""
def add(self, x, y):
return x + y
def sub(self, x, y):
return x - y
def mul(self, x, y):
return x * y
def div(self, x, y):
return x / y
class Proxy(IMath):
"""Прокси"""
def __init__(self):
self.math = Math()
def add(self, x, y):
return self.math.add(x, y)
def sub(self, x, y):
return self.math.sub(x, y)
def mul(self, x, y):
return self.math.mul(x, y)
def div(self, x, y):
if y == 0:
return float('inf') # Вернуть positive infinity
return self.math.div(x, y)
p = Proxy()
x, y = 4, 2
print '4 + 2 = ' + str(p.add(x, y))
print '4 - 2 = ' + str(p.sub(x, y))
print '4 * 2 = ' + str(p.mul(x, y))
print '4 / 2 = ' + str(p.div(x, y))
Imports System.Threading
Class MainApp
Shared Sub Main()
' Create math proxy
Dim p As IMath = New MathProxy()
' Do the math
Console.WriteLine("4 + 2 = " & p.Add(4, 2))
Console.WriteLine("4 - 2 = " & p.Subtr(4, 2))
Console.WriteLine("4 * 2 = " & p.Mul(4, 2))
Console.WriteLine("4 / 2 = " & p.Div(4, 2))
' Wait for user
Console.Read()
End Sub
End Class
''' <summary>
''' Subject - субъект
''' </summary>
''' <remarks>
''' <li>
''' <lu>определяет общий для <see cref="Math"/> и <see cref="Proxy"/> интерфейс, так что класс
''' <see cref="Proxy"/> можно использовать везде, где ожидается <see cref="Math"/></lu>
''' </li>
''' </remarks>
Public Interface IMath
Function Add(ByVal x As Double, ByVal y As Double) As Double
Function Subtr(ByVal x As Double, ByVal y As Double) As Double
Function Mul(ByVal x As Double, ByVal y As Double) As Double
Function Div(ByVal x As Double, ByVal y As Double) As Double
End Interface
''' <summary>
''' RealSubject - реальный объект
''' </summary>
''' <remarks>
''' <li>
''' <lu>определяет реальный объект, представленный заместителем</lu>
''' </li>
''' </remarks>
Class Math
Implements IMath
Public Sub New()
Console.WriteLine("Create object Math. Wait...")
Thread.Sleep(1000)
End Sub
Public Function Add(ByVal x As Double, ByVal y As Double) As Double Implements IMath.Add
Return x + y
End Function
Public Function Subtr(ByVal x As Double, ByVal y As Double) As Double Implements IMath.Subtr
Return x - y
End Function
Public Function Mul(ByVal x As Double, ByVal y As Double) As Double Implements IMath.Mul
Return x * y
End Function
Public Function Div(ByVal x As Double, ByVal y As Double) As Double Implements IMath.Div
Return x / y
End Function
End Class
''' <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
Implements IMath
Private math As Math = Nothing
''' <summary>
''' Быстрая операция - не требует реального субъекта
''' </summary>
Public Function Add(ByVal x As Double, ByVal y As Double) As Double Implements IMath.Add
Return x + y
End Function
Public Function Subtr(ByVal x As Double, ByVal y As Double) As Double Implements IMath.Subtr
Return x - y
End Function
''' <summary>
''' Медленная операция - требует создания реального субъекта
''' </summary>
Public Function Mul(ByVal x As Double, ByVal y As Double) As Double Implements IMath.Mul
If math Is Nothing Then
math = New Math()
End If
Return math.Mul(x, y)
End Function
Public Function Div(ByVal x As Double, ByVal y As Double) As Double Implements IMath.Div
If math Is Nothing Then
math = New Math()
End If
Return math.Div(x, y)
End Function
End Class
См. также
Литература
Ссылки
- Паттерн Proxy (заместитель) — назначение, описание, особенности и реализация на С++.