Proxy controls access to another object. That access control might mean security checks, caching, lazy initialization, rate limiting, or remote communication.
Example Problem
Generating a report is expensive. Only admin users may access it, and repeated requests for the same report should be cached.
UML
classDiagram
class ReportService {
<<interface>>
+getReport(String, UserContext) String
}
class RealReportService
class SecuredCachedReportProxy
ReportService <|.. RealReportService
ReportService <|.. SecuredCachedReportProxy
SecuredCachedReportProxy --> RealReportService
Implementation Walkthrough
import java.util.HashMap;
import java.util.Map;
public interface ReportService {
String getReport(String reportId, UserContext userContext);
}
public final class RealReportService implements ReportService {
@Override
public String getReport(String reportId, UserContext userContext) {
return "Expensive report payload for " + reportId;
}
}
public final class SecuredCachedReportProxy implements ReportService {
private final ReportService delegate;
private final Map<String, String> cache = new HashMap<>();
public SecuredCachedReportProxy(ReportService delegate) {
this.delegate = delegate;
}
@Override
public String getReport(String reportId, UserContext userContext) {
if (!userContext.isAdmin()) {
throw new SecurityException("Admin role required");
}
return cache.computeIfAbsent(reportId, id -> delegate.getReport(id, userContext));
}
}
Usage:
ReportService reportService = new SecuredCachedReportProxy(new RealReportService());
String report = reportService.getReport("sales-monthly", new UserContext("sandeep", true));
The proxy performs two distinct control tasks before the expensive service does any work:
- it rejects unauthorized callers
- it avoids repeated work through caching
That is why Proxy fits better than a plain helper method here. The caller still sees the same ReportService contract, but access to the real object is now governed by policy.
Why Proxy Fits Better Than Decorator Here
Decorator and Proxy look structurally similar. The difference is intent.
- Decorator adds behavior as part of business composition
- Proxy controls access to the real object
This example is fundamentally about gatekeeping access and shielding an expensive service.
As the policy grows, the proxy can evolve to support TTL, tenant-aware cache keys, or remote call protection without changing client code.
Production Notes
Real proxies often add:
- TTL-based caches
- permission scopes
- remote client retries
- circuit breaking
At that point the proxy becomes operationally important, so its behavior must be documented and tested.