Proxy pattern
Proxy pattern is one of the structural design patterns
As the name indicates, this pattern is used to define a proxy for a real object.
We know that proxy means, something in place of other thing or just a representation of something else.
Let’s understand Proxy Pattern in this way
We have some heavy object which contains lot of methods in it but always it is not required to use all the methods of the complex heavy object.
So, in this case, we will use some light objects which exposes the same interface as heavy object.
Using that, we can use only required methods of heavy object
So,This light object is called as “Proxy”
Proxy object acts like a real object but its not the actual real object.
Client basically access Proxy object and Proxy object in turn access real object,In this way it also helps to control the access of real object.
Controlling the access of the real objects has many benefits
1) Controlling when a costly object needs to be instantiated
2) Giving different access rights based on some roles to an object
3) Providing a sophisticated way of accessing and referencing remote objects(objects in other system)
Now let’s try to understand technically and implement it
In this pattern, client basically access Proxy object
Proxy object access actual object
So, we will have a common interface for both actual object and Proxy object
We can see the same in below diagram
Subject – Interface implemented by the RealObject and representing its services. The interface must be implemented by the ProxyObject as well so that the proxy can be used in any location where the RealObject can be used.
ProxyObject
Proxy class to access the RealObject.
Implements the same interface implemented by the RealObject so that the Proxy can be substituted for the RealObject.
Controls access to the RealObject and also responsible for its creation and deletion.
There could be other responsibilities depend on the kind of proxy we are using.
RealObject – The real object that the proxy represents.
Let’s implement Proxy pattern for below requirement
Requirement :
In email application, we use attachments sometime while sending an email.
User who reads an email might open an attachment or might not
So, send an attachment link only in the email rather than sending whole attachment content.
So that when user opens an attachment, we can load the attachment content.
Also control the access of real object to show attachment only for valid users
In this case, we use proxy pattern and send proxy object as an attachment which should call real object only when user opens an attachment.
Let’s achieve it by coding
Step 1
Create an interface called “Email”
- package com.kb.proxy;
- public interface Email {
- public void showEmail(String user);
- }
package com.kb.proxy; public interface Email { public void showEmail(String user); }
Step 2
Create a proxy class which implements this interface
- package com.kb.proxy;
- import java.util.ArrayList;
- import java.util.List;
- public class EmailProxy implements Email {
- private static List<String> userList;
- static {
- userList = new ArrayList<String>();
- userList.add("111");
- userList.add("222");
- userList.add("333");
- }
- @Override
- public void showEmail(String user) {
- if (userList.contains(user)) {
- Email email = new EmailWithAttachment();
- email.showEmail(user);
- } else {
- throw new RuntimeException("Sorry, Access Denied");
- }
- }
- }
package com.kb.proxy; import java.util.ArrayList; import java.util.List; public class EmailProxy implements Email { private static List<String> userList; static { userList = new ArrayList<String>(); userList.add("111"); userList.add("222"); userList.add("333"); } @Override public void showEmail(String user) { if (userList.contains(user)) { Email email = new EmailWithAttachment(); email.showEmail(user); } else { throw new RuntimeException("Sorry, Access Denied"); } } }
Step 3
Create a real implementor class which implements this interface
- package com.kb.proxy;
- public class EmailWithAttachment implements Email{
- @Override
- public void showEmail(String user) {
- System.out.println("Heavy operation to load attachment is done");
- }
- }
package com.kb.proxy; public class EmailWithAttachment implements Email{ @Override public void showEmail(String user) { System.out.println("Heavy operation to load attachment is done"); } }
Step 4
Create client class which uses the proxy
- package com.kb.proxy;
- public class EmailViewer {
- public static void main(String[] args) {
- Email email = new EmailProxy(); //Loading only proxy object
- //calling with valid user, This will actually loads real object
- email.showEmail("111");
- //calling with invalid user, This will also loads real object
- email.showEmail("444");
- }
- }
package com.kb.proxy; public class EmailViewer { public static void main(String[] args) { Email email = new EmailProxy(); //Loading only proxy object //calling with valid user, This will actually loads real object email.showEmail("111"); //calling with invalid user, This will also loads real object email.showEmail("444"); } }
Step 5
Run the client program and check the output
- Heavy operation to load attachment is done
- java.lang.RuntimeException: Sorry, Access Denied
- at com.kb.proxy.EmailProxy.showEmail(EmailProxy.java:23)
- at com.kb.proxy.EmailViewer.main(EmailViewer.java:12)
Heavy operation to load attachment is done java.lang.RuntimeException: Sorry, Access Denied at com.kb.proxy.EmailProxy.showEmail(EmailProxy.java:23) at com.kb.proxy.EmailViewer.main(EmailViewer.java:12)
We can see that,
For valid user, proxy is making a call to real object and get the ouput
For Invalid user, proxy is not making a call to real object and throwing exception.
Proxy pattern is very similar to decorator pattern in the structure but decorator adds responsibilities to an object while a proxy controls access to it
When should we use Proxy pattern?
Whenever we need to provide a surrogate or placeholder for another object to control access to it
Whenever we need to add a wrapper to protect the real object
Whenever we need to load few details of the complex object and loading remaining details as and when required
Note :
This pattern is already implemented in Java Remote Method invocation(RMI) and Hibernate lazy loading