Proxy objects or the surrogates provide a placeholder for another object to control access to that object. A proxy acts as a lightweight or the simplified version of the original object. It supports the same operations as the original object but may delegate those requests to the original object to achieve them.
The Proxy design pattern is a structural pattern in which a proxy class wraps the real subject class. The client code only interacts with the proxy class and not the real subject.
In this tutorial, we’ll learn how to implement a proxy design pattern.
There are three most common scenarios where we might need a proxy class:
A Proxy design pattern has the following components:
Both the Proxy and RealSubject classes implement the Subject interface. Also, the client interacts with the Subject interface and so it hides the fact that the client is interacting with a proxy in place of the real subject.
The proxy class wraps the real subject and may delegate some requests to the real subject. However, not all requests are delegated to the subject class. A proxy is capable of handling some of the lighter responsibilities.
Most of the organizations provide restricted access to the internet within their premises. So, how is it implemented?
The idea is to create a protection proxy.
Let’s start by defining a WebServer interface:
public interface WebServer { void makeRequest(String url); }
Here, the makeRequest() method is responsible for making a call to the webserver with a specific endpoint.
Let’s now implement the RealWebServer class which does the actual job of hitting a URL via network API calls:
public class RealWebServer implements WebServer { @Override public void makeRequest(String url) { //code to hit a particular url } }
Finally, we’ll create a proxy server and expose it to our clients:
public class ProxyWebServer implements WebServer { private RealWebServer realServer; private List<String> blockedSites = new ArrayList<>(); public ProxyWebServer() { this.realServer = new RealWebServer(); } public void blockWebsite(String url) { this.blockedSites.add(url); } @Override public void makeRequest(String url) { if(!blockedSites.contains(url)) { this.realServer.makeRequest(url); } else { System.out.println("This website is blocked. Contact your administrator"); } } }
With this, all the blocked websites will remain unavailable within the premises:
//code in main method WebServer server = new ProxyWebServer(); server.blockWebsite("www.facebook.com"); ... server.makeRequest("www.facebook.com"); // Prints 'This website is blocked. Contact your administrator'
In this tutorial, we explored the proxy design pattern.
A proxy pattern allows us to defer creating an expensive resource until it’s needed, control access to the real subject, or to represent a remote object locally.
The Java Reflection API relies on proxies. Also, the Hibernate lazy fetching logic internally makes use of this pattern.