Proxy pattern
In computer programming, the proxy pattern is a software design pattern. A proxy, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate. In short, a proxy is a wrapper or agent object that is being called by the client to access the real serving object behind the scenes. Use of the proxy can simply be forwarding to the real object, or can provide additional logic. In the proxy, extra functionality can be provided, for example caching when operations on the real object are resource intensive, or checking preconditions before operations on the real object are invoked. For the client, usage of a proxy object is similar to using the real object, because both implement the same interface.
Overview
The Proxydesign pattern is one of the twenty-three well-known
GoF design patterns
that describe how to solve recurring design problems to design flexible and reusable object-oriented software, that is, objects that are easier to implement, change, test, and reuse.
What problems can the Proxy design pattern solve?
- The access to an object should be controlled.
- Additional functionality should be provided when accessing an object.
What solution does the Proxy design pattern describe?
Define a separateProxy
object that - can be used as substitute for another object and
- implements additional functionality to control the access to this subject.
Proxy
object to perform additional functionality when accessing a subject. For example, to check the access rights of clients accessing a sensitive object.To act as substitute for a subject, a proxy must implement the
Subject
interface.Clients can't tell whether they work with a subject or its proxy.
See also the UML class and sequence diagram below.
Structure
UML class and sequence diagram
In the above UML class diagram,the
Proxy
class implements the Subject
interface so that it can act as substitute for Subject
objects. It maintains a reference to the substituted object so that it can forward requests to it
.
The sequence diagram
shows the run-time interactions: The
Client
object works through a
Proxy
object thatcontrols the access to a
RealSubject
object.In this example, the
Proxy
forwards the request to the RealSubject
, which performs the request.Class diagram
Possible usage scenarios
Remote proxy
In distributed object communication, a local object represents a remote object. The local object is a proxy for the remote object, and method invocation on the local object results in remote method invocation on the remote object. An example would be an ATM implementation, where the ATM might hold proxy objects for bank information that exists in the remote server.Virtual proxy
In place of a complex or heavy object, a skeleton representation may be advantageous in some cases. When an underlying image is huge in size, it may be represented using a virtual proxy object, loading the real object on demand.Protection proxy
A protection proxy might be used to control access to a resource based on access rights.Example
PHP
interface Image
// On System A
class RealImage implements Image
// On System B
class ProxyImage implements Image
$image1 = new ProxyImage;
$image2 = new ProxyImage;
$image1->displayImage; // Loading necessary
$image1->displayImage; // Loading unnecessary
$image2->displayImage; // Loading necessary
$image2->displayImage; // Loading unnecessary
$image1->displayImage; // Loading unnecessary
The program's output is:
Loading HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Loading HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo1
C#
interface ICar
// Real Object
public class Car : ICar
// Proxy Object
public class ProxyCar : ICar
public class Driver
// How to use above Proxy class?
private void btnProxy_Click
Output
Sorry, the driver is too young to drive.
Car has been driven!
Notes:
- A proxy may hide information about the real object to the client.
- A proxy may perform optimization like on demand loading.
- A proxy may do additional house-keeping job like audit tasks.
- Proxy design pattern is also known as surrogate design pattern.
C++
- include
- include
class Car : public ICar ;
class ProxyCar : public ICar ;
int main
Crystal
abstract class AbstractCar
abstract def drive
end
class Car < AbstractCar
def drive
puts "Car has been driven!"
end
end
class Driver
getter age : Int32
def initialize
end
end
class ProxyCar < AbstractCar
private getter driver : Driver
private getter real_car : AbstractCar
def initialize
@real_car = Car.new
end
def drive
if driver.age <= 16
puts "Sorry, the driver is too young to drive."
else
@real_car.drive
end
end
end
- Program
car = ProxyCar.new
car.drive
driver = Driver.new
car = ProxyCar.new
car.drive
Output
Sorry, the driver is too young to drive.
Car has been driven!
Delphi / Object Pascal
// Proxy Design pattern
unit DesignPattern.Proxy;
interface
type
// Car Interface
ICar = interface
procedure DriveCar;
end;
// TCar class, implementing ICar
TCar = Class
class function New: ICar;
procedure DriveCar;
End;
// Driver Interface
IDriver = interface
function Age: Integer;
end;
// TDriver Class, implementing IDriver
TDriver = Class
private
FAge: Integer;
public
constructor Create; Overload;
class function New: IDriver;
function Age: Integer;
End;
// Proxy Object
TProxyCar = Class
private
FDriver: IDriver;
FRealCar: ICar;
public
constructor Create; Overload;
class function New: ICar;
procedure DriveCar;
End;
implementation
class function TCar.New: ICar;
begin
Result := Create;
end;
procedure TCar.DriveCar;
begin
WriteLn;
end;
constructor TDriver.Create;
begin
inherited Create;
FAge := Age;
end;
class function TDriver.New: IDriver;
begin
Result := Create;
end;
function TDriver.Age: Integer;
begin
Result := FAge;
end;
constructor TProxyCar.Create;
begin
inherited Create;
Self.FDriver := Driver;
Self.FRealCar := TCar.Create AS ICar;
end;
class function TProxyCar.New: ICar;
begin
Result := Create;
end;
procedure TProxyCar.DriveCar;
begin
if
then WriteLn
else FRealCar.DriveCar;
end;
end.
Usage
program Project1;
uses
DesignPattern.Proxy in 'DesignPattern.Proxy.pas';
begin
TProxyCar.New.DriveCar;
TProxyCar.New.DriveCar;
end.
Output
Sorry, the driver is too young to drive.
Car has been driven!
Java
The following Java example illustrates the "virtual proxy" pattern. The ProxyImage class is used to access a remote method.The example creates first an interface against which the pattern creates the classes. This interface contains only one method to display the image, called displayImage, that has to be coded by all classes implementing it.
The proxy class ProxyImage is running on another system than the real image class itself and can represent the real image RealImage over there. The image information is accessed from the disk. Using the proxy pattern, the code of the ProxyImage avoids multiple loading of the image, accessing it from the other system in a memory-saving manner. The lazy loading demonstrated in this example is not part of the proxy pattern, but is merely an advantage made possible by the use of the proxy.
interface Image
// On System A
class RealImage implements Image
// On System B
class ProxyImage implements Image
class ProxyExample
The program's output is:
Loading HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Loading HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo1
Python
"""
Proxy pattern example.
"""
from abc import ABCMeta, abstractmethod
NOT_IMPLEMENTED = "You should implement this."
class AbstractCar:
__metaclass__ = ABCMeta
@abstractmethod
def drive:
raise NotImplementedError
class Car:
def drive -> None:
class Driver:
def __init__ -> None:
self.age = age
class ProxyCar:
def __init__ -> None:
self.car = Car
self.driver = driver
def drive -> None:
if self.driver.age <= 16:
else:
self.car.drive
driver = Driver
car = ProxyCar
car.drive
driver = Driver
car = ProxyCar
car.drive
Rust
trait ICar
struct Car
impl ICar for Car
impl Car
struct ProxyCar<'a>
impl<'a> ICar for ProxyCar<'a>
impl<'a> ProxyCar<'a>
#
mod tests