Deputy ( Eng. Proxy ) - a structural design template that provides an object that controls access to another object, intercepting all calls (performs the function of a container ).
| Deputy | |
|---|---|
| Proxy | |
| Type of | structural |
| Appointment | Provides a surrogate object that controls access to another object. |
| pros |
|
| Minuses |
|
| Described in Design Patterns | Yes |
Content
- 1 Goal
- 1.1 Problem
- 1.2 Solution
- 2 Types
- 3 Advantages and disadvantages of the application
- 3.1 Benefits
- 3.2 Disadvantages
- 4 Scope
- 5 Proxies and related templates [1]
- 6 Implementation Examples
- 6.1 Java
- 6.2 Scala
- 6.3 C ++
- 6.4 C #
- 6.5 JavaScript
- 6.6 Ruby
- 6.7 PHP5
- 6.8 ActionScript
- 6.9 Python
- 6.10 VB.NET
- 7 See also
- 8 Notes
- 9 Literature
- 10 Links
Purpose
Problem
It is necessary to control access to the object without changing the behavior of the client.
You must have access to the object so as not to create real objects directly, but through another object, which may have additional functionality.
Solution
Create a surrogate for a real object. The “Deputy” stores a link that allows the Deputy to refer to the real subject (the object of the “Deputy” class can access the object of the “Subject” class if the interfaces of the “Real Subject” and “Subject” are the same). Since the interface of the "Real Subject" is identical to the interface of the "Subject", so that the "Deputy" can be substituted for the "Real Subject", controls access to the "Real Subject", may be responsible for creating or deleting the "Real Subject". “Subject” defines a common interface for the “Real Subject” and the “Deputy” so that the “Deputy” can be used wherever the “Real Subject” is expected. If necessary, requests can be redirected by the “Deputy” to the “Real Subject”.
Views
- Protocol proxy : saves all calls of the “Subject” with their parameters to the log.
- Remote proxies : provides communication with the “Subject” located in another address space or on a remote machine. It may also be responsible for encoding the request and its arguments and sending the encoded request to the real “Subject”,
- Virtual proxies : ensures the creation of a real “Subject” only when it is really needed. It can also cache part of the information about the real “Subject” to delay its creation,
- Copy-on-write : provides copying of the “subject” when the client performs certain actions (a special case of the “virtual proxy”).
- Protection proxies : can check if the caller has the rights necessary to execute the request.
- Caching proxy : provides temporary storage of calculation results until they are returned to multiple clients who can share these results.
- Screening proxy : protects the Subject from dangerous clients (or vice versa).
- Synchronizing proxy : performs synchronized access control to the "Subject" in an asynchronous multi - threaded environment.
- Smart link proxy : performs additional actions when a link is created to the “Subject”, for example, it calculates the number of active links to the “Subject”.
Advantages and disadvantages of the application
Benefits
- remote substitute;
- virtual substitute can perform optimization;
- protecting substitute;
- “Smart” link (pointer) ;
Weaknesses
- a sharp increase in response time.
Scope
The Proxy template can be used in cases of working with a network connection, with a huge object in memory (or on disk), or with any other resource that is difficult or difficult to copy. A well-known application example is an object that counts the number of links.
Proxies and related templates [1]
- The adapter provides a different interface to the object.
- A proxy provides the same interface.
- The decorator provides an advanced interface.
Implementation Examples
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 double add ( double x , double y ) {
lazyInitMath ();
return math . add ( x , y );
}
public double sub ( double x , double y ) {
lazyInitMath ();
return math . sub ( x , y );
}
public double mul ( double x , double y ) {
lazyInitMath ();
return math . mul ( x , y );
}
public double div ( double x , double y ) {
lazyInitMath ();
return math . div ( x , y );
}
private void lazyInitMath () {
if ( math == null ) {
math = new Math ();
}
}
}
Scala
object Main extends App {
val p : IMath = new MathProxy
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"
* /
trait IMath {
def add ( x : Double , y : Double ) : Double
def sub ( x : Double , y : Double ) : Double
def mul ( x : Double , y : Double ) : Double
def div ( x : Double , y : Double ) : Double
}
/ **
* "Real Subject"
* /
class Math extends IMath {
def add ( x : Double , y : Double ) = x + y
def sub ( x : Double , y : Double ) = x - y
def mul ( x : Double , y : Double ) = x * y
def div ( x : Double , y : Double ) = x / y
}
/ **
* "Proxy Object"
* /
class MathProxy extends IMath {
private lazy val math = new Math
def add ( x : Double , y : Double ) = math . add ( x , y )
def sub ( x : Double , y : Double ) = math . sub ( x , y )
def mul ( x : Double , y : Double ) = math . mul ( x , y )
def div ( x : Double , y : Double ) = math . div ( x , y )
}
C ++
/ **
* "Subject"
* /
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 ;
}
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 - subject
/// </summary>
/// <remarks>
/// <li>
/// <lu> defines a common interface for <see cref = "Math" /> and <see cref = "Proxy" />, so the class
/// <see cref = "Proxy" /> can be used wherever expected <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 - the real object
/// </summary>
/// <remarks>
/// <li>
/// <lu> defines the real object represented by the substitute </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 - Deputy
/// </summary>
/// <remarks>
/// <li>
/// <lu> stores a link that allows the substitute to access the real
/// subject. The class object <see cref = "MathProxy" /> can access the class object
/// <see cref = "IMath" /> if the interfaces of the classes <see cref = "Math" /> and <see cref = "IMath" /> are the same; </lu>
/// <lu> provides an interface identical to the <see cref = "IMath" /> interface, so the substitute
/// can always be provided instead of the real subject; </lu>
/// <lu> controls access to the real subject and may be responsible for its creation
/// and delete; </lu>
/// <lu> other duties depend on the type of substitute:
/// <li>
/// <lu> <b> remote deputy </b> is responsible for encoding the request and its arguments
/// and sending the encoded request to the real subject in
/// another address space; </lu>
/// <lu> <b> virtual substitute </b> may cache additional information
/// about the real subject, to postpone its creation. </lu>
/// <lu> <b> protecting substitute </b> checks to see if the caller has
/// necessary to execute the request rights; </lu>
/// </li>
/// </lu>
/// </li>
/// </remarks>
class MathProxy : IMath
{
Math math ;
public MathProxy ()
{
math = null ;
}
/// <summary>
/// Fast operation - does not require a real subject
/// </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>
/// Slow operation - requires the creation of a real subject
/// </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); // aggregate IMath, because no native inheritance
// this option should be used instead of prototyping,
// if there are private variables in IMath,
// which can be accessed via getters in 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 )); // one
Ruby
module ProxyPattern
# Proxy has the same interface like a Real Subject
# Real Subject
class account
attr_reader : balance
def initialize ( balance = 0 )
@balance = balance
end
def deposit ( amount )
@balance + = amount
end
def withdraw ( amount )
@balance - = amount
end
end
module protection
# Additional functionality to control the access to the realSubject
# Proxy
class AccountProxy
def initialize ( subject , current_user )
@subject = subject
@current_user = current_user
@balance = 0
end
def deposit ( amount )
@subject . deposit ( amount ) if authorize
end
def withdraw ( amount )
@subject . withdraw ( amount ) if authorize
end
def balance
@subject . balance
end
private
def authorize
puts 'Access denied' unless @current_user == 'admin'
@current_user == 'admin'
end
end
def self . run
puts '=> Proxy :: Protection'
puts 'as user'
protected_account = AccountProxy . new ( Account . new , 'user' )
protected_account . deposit ( 20 )
protected_account . withdraw ( 10 )
puts protected_account . balance
puts 'as admin'
protected_account = AccountProxy . new ( Account . new , 'admin' )
protected_account . deposit ( 20 )
protected_account . withdraw ( 10 )
puts protected_account . balance
puts ''
end
end
module virtual
# Delay realSubject loading (lazy loading)
# Proxy
class AccountProxy
def initialize ( local_balance = 0 )
@local_balance = local_balance
end
def deposit ( amount )
@local_balance + = amount
end
def withdraw ( amount )
@local_balance - = amount
end
def balance
subject . balance
end
def subject
@subject || = Account . new ( @local_balance )
end
end
def self . run
puts '=> Proxy :: Virtual'
local_account = AccountProxy . new
local_account . deposit ( 20 )
local_account . withdraw ( 10 )
local_account . deposit ( 15 )
local_account . withdraw ( 5 )
puts 'No real account yet:'
puts local_account . inspect
local_account . balance
puts 'Real account was created:'
puts local_account . inspect
puts ''
end
end
def self . run
Protection run
Virtual run
end
end
PHP5
<? php
/// Subject - subject
/// defines a common interface for Math and "Proxy", so the class
/// "Proxy" can be used wherever expected
interface IMath
{
function Add ( $ x , $ y );
function Sub ( $ x , $ y );
function Mul ( $ x , $ y );
function Div ( $ x , $ y );
}
/// RealSubject - the real object
/// defines the real object represented by the substitute
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 - Deputy
/// stores a link that allows the substitute to access the real
/// subject. An object of class "MathProxy" can access an object of class
/// "Math" if the interfaces of the classes "Math" and "IMath" are the same;
/// provides an interface identical to the IMath interface, so the substitute
/// can always be provided instead of the real subject;
/// controls access to the real subject and may be responsible for its creation
/// and delete;
/// other duties depend on the type of substitute:
/// remote substitute is responsible for encoding the request and its arguments
/// and sending the encoded request to the real subject in
/// another address space;
/// virtual substitute can cache additional information
/// about the real subject, to postpone its creation.
/// protecting substitute checks to see if the caller has
/// necessary to execute the request rights;
class MathProxy implements IMath
{
protected $ math ;
public function __construct ()
{
$ this -> math = null ;
}
/// Fast operation - does not require a real subject
public function Add ( $ x , $ y )
{
return $ x + $ y ;
}
public function Sub ( $ x , $ y )
{
return $ x - $ y ;
}
/// Slow operation - requires the creation of a real subject
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 ));
?>
ActionScript
// IMath.as file
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 ;
}
}
// file 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 ;
}
}
}
// file 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 file
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 ));
}
}
}
Python
# - * - coding: utf-8 - * -
class IMath :
"" "Interface for proxy and real subject" ""
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 ):
"" "The real subject" ""
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 ):
"" "Proxy" ""
def __init__ ( self ):
self . math = None
# Fast operations - do not require a real subject
def add ( self , x , y ):
return x + y
def sub ( self , x , y ):
return x - y
# Slow operation - requires the creation of a real subject
def mul ( self , x , y ):
if not self . math :
self . math = Math ()
return self . math . mul ( x , y )
def div ( self , x , y ):
if y == 0 :
return float ( 'inf' ) # Return positive infinity
if not self . math :
self . math = Math ()
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 ))
VB.NET
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 - subject
'' '</summary>
'' '<remarks>
'' '<li>
'' '<lu> defines a common interface for <see cref = "Math" /> and <see cref = "Proxy" /> interface, so the class
'' '<see cref = "Proxy" /> can be used wherever expected <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 - the real object
'' '</summary>
'' '<remarks>
'' '<li>
'' '<lu> defines the real object represented by the substitute </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 - Deputy
'' '</summary>
'' '<remarks>
'' '<li>
'' '<lu> stores a link that allows the substitute to access the real
'' 'to the subject. The class object <see cref = "MathProxy" /> can access the class object
'' '<see cref = "IMath" /> if the interfaces of the classes <see cref = "Math" /> and <see cref = "IMath" /> are the same; </lu>
'' '<lu> provides an interface identical to the <see cref = "IMath" /> interface, so the substitute
'' 'can always be provided instead of the real subject; </lu>
'' '<lu> controls access to the real subject and may be responsible for its creation
'' 'and deletion; </lu>
'' '<lu> other duties depend on the type of substitute:
'' '<li>
'' '<lu> <b> remote substitute </b> is responsible for encoding the request and its arguments
'' 'and sending the encoded request to the real subject in
'' 'another address space; </lu>
'' '<lu> <b> virtual substitute </b> may cache additional information
'' 'about the real subject, to postpone its creation. </lu>
'' '<lu> <b> protecting substitute </b> checks to see if the caller has
'' 'the necessary rights to fulfill the request; </lu>
'' '</li>
'' '</lu>
'' '</li>
'' '</remarks>
Class MathProxy
Implements IMath
Private math As Math = Nothing
'' '<summary>
'' 'Fast operation - does not require a real subject
'' '</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>
'' 'Slow operation - requires the creation of a real subject
'' '</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
See also
- Пост-объектное программирование
Notes
- ↑ Дневники разработчика // Заместитель (Proxy) (недоступная ссылка) . Дата обращения 26 мая 2010. Архивировано 14 мая 2010 года.
Literature
- CodeLIB.YOURS // Заместитель (Proxy)
- Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес . Приемы объектно-ориентированного проектирования. Паттерны проектирования.=Design Patterns.Elements of reusable object-oriented software. — СПб: Питер, 2001. — 368 с. — ISBN 5-272-00355-1 .
- Эрик Фримен, Элизабет Фримен, Кэтти Сьера, Берт Бейтс. Паттерны проектирования. — СПб: Питер, 2012. — 656 с. — ISBN 978-5-459-00435-9 .
Links
- Паттерн Proxy (заместитель) — назначение, описание, особенности и реализация на С++.