23-10-2023
Заместитель | |
Proxy | |
Тип: |
структурный |
---|---|
Описан в Design Patterns |
Да |
Шаблон Proxy (определяет объект-заместитель англ. surrogate иначе -заменитель англ. placeholder) — шаблон проектирования, который предоставляет объект, который контролирует доступ к другому объекту, перехватывая все вызовы (выполняет функцию контейнера).
Необходимо управлять доступом к объекту так, чтобы создавать громоздкие объекты «по требованию».
Создать суррогат громоздкого объекта. «Заместитель» хранит ссылку, которая позволяет заместителю обратиться к реальному субъекту (объект класса «Заместитель» может обращаться к объекту класса «Субъект», если интерфейсы «Реального Субъекта» и «Субъекта» одинаковы). Поскольку интерфейс «Реального Субъекта» идентичен интерфейсу «Субъекта», так, что «Заместителя» можно подставить вместо «Реального Субъекта», контролирует доступ к «Реальному Субъекту», может отвечать за создание или удаление «Реального Субъекта». «Субъект» определяет общий для «Реального Субъекта» и «Заместителя» интерфейс, так, что «Заместитель» может быть использован везде, где ожидается «Реальный Субъект». При необходимости запросы могут быть переадресованы «Заместителем» «Реальному Субъекту».
Шаблон proxy бывает нескольких видов, а именно:
Преимущества:
Шаблон Proxy может применяться в случаях работы с сетевым соединением, с огромным объектом в памяти (или на диске) или с любым другим ресурсом, который сложно или тяжело копировать. Хорошо известный пример применения — объект, подсчитывающий число ссылок.
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 __construct() { 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 (шаблон проектирования).