Structural Design Patterns
Sometimes, you need more than just a direct reference to an object. Direct access might be inefficient, insecure, or impractical. Consider these scenarios:
deleteEverything() method. You can't let just any part of the application call this method directly. You need a way to check the user's permissions before allowing the call to proceed.In all these cases, the problem is the same: you need to put something in between the client and the real object to manage the interaction.
The Proxy is a structural design pattern that provides a surrogate or placeholder for another object to control access to it.
The key feature of the Proxy pattern is that the Proxy object has the exact same interface as the real object it represents. This makes the proxy "transparent" to the client. The client code is written as if it's talking directly to the real object, but it's actually talking to the Proxy. The Proxy then decides if, when, and how to delegate the request to the real object (often called the "Real Subject").
The best real-world analogy is a debit card. It's a proxy for your bank account. You can use it to "pay" just like you would with cash (it has the same interface), but it adds a layer of control: it performs security checks, verifies your PIN, and checks your spending limit before allowing the transaction to go through to your actual bank funds.
RealSubject and the Proxy. This is what makes them interchangeable and keeps the proxy transparent to the client.RealSubject. It holds a reference to the RealSubject and can manage its lifecycle (e.g., creating it on demand). It performs its control logic before or after delegating the call to the RealSubject.Let's implement a "Protection Proxy" to secure access to an internet connection, banning certain sites.
Step 1: The Subject Interface
public interface IInternet {
void connectTo(String serverHost) throws Exception;
}
Step 2: The Real Subject
This class provides the core, unfiltered internet access.
public class RealInternet implements IInternet {
@Override
public void connectTo(String serverHost) {
System.out.println("Connecting to " + serverHost);
}
}
Step 3: The Proxy Class
This proxy implements the same interface but adds a layer of security checks.
import java.util.ArrayList;
import java.util.List;
public class ProxyInternet implements IInternet {
private final IInternet realInternet = new RealInternet();
private static final List<String> bannedSites;
static {
bannedSites = new ArrayList<>();
bannedSites.add("banned.com");
bannedSites.add("danger.net");
}
@Override
public void connectTo(String serverHost) throws Exception {
// This is the control logic added by the proxy.
if (bannedSites.contains(serverHost.toLowerCase())) {
throw new Exception("Access Denied to " + serverHost);
}
// If the check passes, delegate the call to the real object.
realInternet.connectTo(serverHost);
}
}
Step 4: The Client Code
The client code works with the IInternet interface and is unaware of the proxy's existence.
public class Client {
public static void main(String[] args) {
IInternet internet = new ProxyInternet(); // The client gets the proxy object
try {
internet.connectTo("google.com");
internet.connectTo("banned.com");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
// Output:
// Connecting to google.com
// Access Denied to banned.com
Benefits:
Drawbacks:
In an interview, it's very impressive to name and describe the common types of proxies:
The Proxy pattern is fundamental for managing object interactions and is a key part of many modern frameworks.
The "Wrapper" Pattern Comparison:
Real-World Examples:
User object's list of Orders is often a proxy that only queries the database when the list is first accessed.@Transactional) and security (@PreAuthorize) before or after your methods execute.