The GoF book says you can use the
Proxy design pattern to, “Provide a surrogate or
placeholder
for another object to control access to it”.
The
Proxy design pattern is your best friend when you have a remote object you want
to work with and make that object seem local, or when you want to control
access to that remote object in some way.
Proxy means ‘in place of’. In attendance roll call, we give proxy for our friends in college right? ‘Representing’ or ‘in place of’ or ‘on behalf of’ are literal meanings of proxy and that directly explains proxy design pattern.
Proxy means ‘in place of’. In attendance roll call, we give proxy for our friends in college right? ‘Representing’ or ‘in place of’ or ‘on behalf of’ are literal meanings of proxy and that directly explains proxy design pattern.
You need to support resource-hungry
objects, and you do not want to instantiate such objects unless and until they
are actually requested by the client.
There are various connection techniques you can use in
Java, such as RMI, to enable proxies to talk to remote objects. Since all you
have to do is send text back and forth from automate proxy to automate server.
Sometimes we need the ability to
control the access to an object. For example if we need to use only a few
methods of some costly objects we'll initialize those objects when we need them
entirely. Until that point we can use some light objects exposing the same
interface as the heavy objects. These light objects are called proxies and they
will instantiate those heavy objects when they are really need and by then
we'll use some light objects instead.
Intent
- Provide a surrogate or placeholder for another object to control access to it.
- Use an extra level of indirection to support distributed, controlled, or intelligent access.
- Add a wrapper and delegation to protect the real component from undue complexity.
There are four common situations in
which the Proxy pattern is applicable.
1)
A virtual proxy is a placeholder
for "expensive to create" objects. The real object is only created
when a client first requests/accesses the object.
e.g. In
place of a complex or heavy object use a skeleton representation. When an
underlying image is huge in size, just represent it using a virtual proxy
object and on demand load the real object.
2)
A remote proxy provides a local
representative for an object that resides in a different address space. This is
what the "stub" code in RPC and CORBA provides.
E.g Think of
an ATM implementation, it will hold proxy objects for bank information that
exists in the remote server , Remote Server Object RMI
3)
protective proxy controls
access to a sensitive master object. The "surrogate" object checks
that the caller has the access permissions required prior to forwarding the request.
4) Smart Reference – Just we keep a
link/reference to the real object a kind of pointer.
A smart proxy
interposes additional actions when an object is accessed. Typical uses include:
i)
Counting
the number of references to the real object so that it can be freed
automatically when there are no more references (aka smart pointer),
ii)
Loading
a persistent object into memory when it's first referenced,
iii)
Checking
that the real object is locked before it is accessed to ensure that no other
object can change it.
Common situation: Java Proxy objects
- Virtual Proxies: delaying the creation and initialization of expensive objects until needed, where the objects are created on demand (For example creating the RealSubject object only when the doSomething method is invoked).
- Remote Proxies: providing a local representation for an object that is in a different address space. A common example is Java RMI stub objects. The stub object acts as a proxy where invoking methods on the stub would cause the stub to communicate and invoke methods on a remote object (called skeleton) found on a different machine.
- Protection Proxies: where a proxy controls access to RealSubject methods, by giving access to some objects while denying access to others.
- Smart References:
providing
a sophisticated access to certain objects such as tracking the number of
references to an object and denying access if a certain number is reached,
as well as loading an object from database into memory on demand.
1: public interface Animal { 2: public void getSound(); 3: }
1: public class Lion implements Animal {
2: @Override
3: public void getSound() {
4: System.out.println("Roar");
5: }
6: }
Below implemented InvocationHandler
1: import java.lang.reflect.InvocationHandler;
2: import java.lang.reflect.Method;
3: public class AnimalInvocationHandler implements InvocationHandler {
4: private Object realSubject = null;
5: public AnimalInvocationHandler(Object realSubject) {
6: this.realSubject = realSubject;
7: }
8: @Override
9: public Object invoke(Object proxy, Method method, Object[] args)
10: throws Throwable {
11: Object result = null;
12: try {
13: result = method.invoke(realSubject, args);
14: } catch (Exception ex) {
15: ex.printStackTrace();
16: }
17: return result;
18: }
19: }
Test Class
1: import java.lang.reflect.Proxy;
2: public class ProxyExample {
3: public static void main(String[] args) {
4: Animal realSubject = new Lion();
5: Animal proxy = (Animal) Proxy.newProxyInstance(realSubject.getClass()
6: .getClassLoader(), realSubject.getClass().getInterfaces(),
7: new AnimalInvocationHandler(realSubject));
8: proxy.getSound();
9: }
10: }
Output : Roar
1: public interface Image {
2: void display();
3: }
Create concrete classes implementing
the same interface.
1: public class RealImage implements Image {
2: private String fileName;
3: public RealImage(String fileName){
4: this.fileName = fileName;
5: loadFromDisk(fileName);
6: }
7: @Override
8: public void display() {
9: System.out.println("Displaying " + fileName);
10: }
11: private void loadFromDisk(String fileName){
12: System.out.println("Loading " + fileName);
13: }
14: }
Implement Proxy class with same interface .
1: public class ProxyImage implements Image {
2: private RealImage realImage;
3: private String fileName;
4: public ProxyImage(String fileName){
5: this.fileName = fileName;
6: }
7: @Override
8: public void display() {
9: if(realImage == null){
10: realImage = new RealImage(fileName);
11: }
12: realImage.display();
13: }
14: }
Use the ProxyImage to get
object of RealImage class when required.
1: public class ProxyPatternDemo {
2: public static void main(String[] args) {
3: Image image = new ProxyImage("test_10mb.jpg");
4: //image will be loaded from disk
5: image.display();
6: System.out.println("");
7: //image will not be loaded from disk
8: image.display();
9: }
10: }
Notes :
1)
Adapter provides a
different interface to its subject. Proxy
provides the same interface. Decorator
provides an enhanced interface.
2)
Adapter
Design Pattern - The adapter implements a different
interface to the object it adapts where a proxy implements the same interface
as its subject.
3)
Decorator Design
Pattern - A decorator implementation can be
the same as the proxy however a decorator adds responsibilities to an object
while a proxy controls access to it.
4) Decorator and Proxy have
different purposes but similar structures. Both describe
how to provide
a level of indirection to another object, and the implementations keep a reference to the object to which they forward requests
- 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.