Skip to content

The Surrogate for Controlled Access

A stand-in that controls access to the real object

Builds on Interfaces

Stage 3core3 min read

The Proxy Pattern Solution

The new code uses the Proxy Pattern (specifically a Caching Proxy). The proxy sits between the client and the costly RealVideoDownloader. Because the client talks to a stand-in object, we control how and when the real service is called.


1. How Proxy Pattern Solves the Issue

Here, the proxy (CachedVideoDownloader class) has caching logic that checks whether a video was already downloaded.

  • Resource Optimization: If the video is in the cache, the proxy returns the cached result. This saves time and network use.
  • Call Only When Needed: The real download runs only on a cache miss, so repeated requests do not trigger the costly network call.
  • Performance Gains: Repeated requests are answered by the proxy, so responses are faster and the whole system does less work.

2. Key Improvements

Separation of Concerns

  • The Benefit: RealVideoDownloader only downloads. CachedVideoDownloader handles the extra work, such as caching.
  • The Impact: The code is easier to maintain and test, because the download logic is not mixed with caching code.

Program to an Interface

  • The Benefit: Both the Proxy and the Real Subject implement the VideoDownloader interface.
  • The Impact: The client does not depend on a specific class. You could swap the cache for a SecurityProxy or a LoggingProxy without changing any code in the Main class.

Housekeeping & Lifecycle Management

  • The Benefit: The Proxy owns the RealVideoDownloader instance, so it could decide when to create it.
  • The Impact: Lazy Initialization is possible, but this demo does not do it. The CachedVideoDownloader constructor creates the RealVideoDownloader at once, and its field uses the concrete class, not the VideoDownloader interface. The demo shows caching only.

3. Structural Breakdown

ComponentResponsibility
Service Interface (VideoDownloader)The shared interface of the Real Subject and the Proxy, so either can be used in the same place.
Real Subject (RealVideoDownloader)The actual object that performs the heavy or sensitive work.
Proxy (CachedVideoDownloader)Controls access to the Real Subject. It can do caching, logging, or access control before or after it hands the work (delegates) to the real object.
Client (Main)Uses the Real Subject or the Proxy through the same interface.

4. Comparison of "Before" vs "After"

FeatureBefore (Direct Access)After (Proxy Pattern)
Network CallsRepeated; hits the server every time.Reduced; hits the server only on a "cache miss" (the video is not in the cache yet).
Response TimeAlways slow, because of network delay (latency).Instant for repeated requests.
ControlNone; anyone can reach the resource.High; the proxy checks and manages access.
ScalabilityPoor; too many requests can overload servers.High; the cache lowers the load on the server.

5. Summary of the "Gatekeeper"

The Proxy Pattern works like an Assistant to a busy executive. Callers do not talk to the executive directly, which would waste the executive's time. The assistant first tries to answer. Only if the assistant does not have the answer do they interrupt the executive.

In this topic

After code1 file

After/Main.java87 linesGitHub
package DesignPatterns.StructuralPatterns.ProxyDesignPattern.After;import java.util.HashMap;import java.util.Map;/** * 1. THE SUBJECT INTERFACE * This common interface allows the Proxy and the RealSubject to be * used interchangeably by the client. */interface VideoDownloader {  String downloadVideo(String videoURL);}/** * 2. THE REAL SUBJECT * This class contains the actual "expensive" business logic. * It should only be called when absolutely necessary. */class RealVideoDownloader implements VideoDownloader {  @Override  public String downloadVideo(String videoUrl) {    // In a real app, this would involve complex network I/O    System.out.println("Connecting to server and downloading: " + videoUrl);    return "High-Quality Video Data from " + videoUrl;  }}/** * 3. THE PROXY (Virtual/Caching Proxy) * This class acts as a gatekeeper. It maintains a reference to the RealSubject * and controls access to it by implementing its own logic (Caching). */class CachedVideoDownloader implements VideoDownloader {  private RealVideoDownloader realDownloader;  private Map<String, String> cache;  public CachedVideoDownloader() {    // The Proxy can manage the lifecycle of the RealSubject    this.realDownloader = new RealVideoDownloader();    this.cache = new HashMap<>();  }  @Override  public String downloadVideo(String videoUrl) {    // GATEKEEPING LOGIC: Check if we already have the resource    if (cache.containsKey(videoUrl)) {      System.out.println(        "PROXY: Found in cache. Returning stored content for: " + videoUrl      );      return cache.get(videoUrl);    }    // DELEGATION: If not in cache, only then call the expensive RealSubject    System.out.println(      "PROXY: Cache miss for " + videoUrl + ". Delegating to RealDownloader..."    );    String video = realDownloader.downloadVideo(videoUrl);    // POST-PROCESSING: Store the result for future requests    cache.put(videoUrl, video);    return video;  }}/** * 4. THE CLIENT * Follows the "Program to an Interface" principle. It doesn't know * it's talking to a Proxy; it just knows it has a VideoDownloader. */class Main {  public static void main(String[] args) {    VideoDownloader videoService = new CachedVideoDownloader();    System.out.println("--- First Request ---");    // This triggers the RealSubject download    videoService.downloadVideo("https://video.com/proxy-pattern");    System.out.println("\n--- Second Request (Same URL) ---");    // This is handled entirely by the Proxy; no network call occurs    videoService.downloadVideo("https://video.com/proxy-pattern");  }}

Done with this topic?

How well do you know it?

PreviousDesign Pattern: Composite (Structural)