Design Patterns Proxy
The Proxy pattern places a stand-in object in front of a real object. Clients talk to the stand-in as if it were the real thing. The proxy decides when, how, and whether the request reaches the real object.
The Real-World Analogy
A receptionist guards an executive's office. Visitors speak to the receptionist, who checks appointments, answers simple questions, and passes serious requests inward. The executive stays focused, and visitors feel they reached the company.
Problem Without a Proxy
Client ───────────────▶ HighResImage (loads 50 MB at creation) Page with 100 images → 5,000 MB loaded, even if the user sees only three.
Solution With a Proxy
Client ──▶ ImageProxy ─ ─ ─ ▶ HighResImage
│ (created only when display() runs)
└── holds filename, cheap to build
The proxy loads the heavy image on the first real request. Pages with hundreds of images open instantly.
Structure
┌───────────────┐
│ «interface» │
│ Image │
│ + display() │
└───────▲───────┘
┌──────┴────────┐
┌────────┴────────┐ ┌────┴─────────────┐
│ RealImage │ │ ImageProxy │
│ + display() │◀│ - real: RealImage│
└─────────────────┘ │ + display() │
└──────────────────┘
Proxy and real object share one interface. Clients cannot tell them apart, which keeps client code unchanged.
Types of Proxy
Virtual Proxy
Delays the creation of a costly object until the first use. The image example above shows this type.
Protection Proxy
Checks permissions before forwarding a call. A document viewer might let guests read a file and block them from editing.
Remote Proxy
Represents an object living on another machine. The proxy handles network details, and the client calls methods like a local object.
Caching Proxy
Stores earlier results and returns them for repeated requests, saving time and bandwidth.
Code Example
interface Image { void display(); }
class RealImage implements Image {
private String file;
RealImage(String file) {
this.file = file;
loadFromDisk(); // slow work
}
public void display() { show(file); }
}
class ImageProxy implements Image {
private String file;
private RealImage real = null;
ImageProxy(String file) { this.file = file; }
public void display() {
if (real == null) {
real = new RealImage(file); // load on first use
}
real.display();
}
}
Image photo = new ImageProxy("beach.jpg"); // fast, nothing loaded yet
photo.display(); // loads now
photo.display(); // reuses loaded imageProxy Compared With Similar Patterns
| Pattern | Purpose |
|---|---|
| Proxy | Controls access to the same interface |
| Decorator | Adds new behavior to the same interface |
| Adapter | Converts one interface into another |
| Facade | Simplifies a group of interfaces |
Advantages and Disadvantages
| Advantages | Disadvantages |
|---|---|
| Controls access without changing the real class | Adds one more class to maintain |
| Saves memory with lazy loading | First call may feel slower |
| Supports caching and logging | Long proxy chains hide the real flow |
Step-by-Step Walkthrough
Follow the image example from start to finish. The client builds an ImageProxy and passes a filename. Storing the name takes the proxy microseconds. Nothing touches the disk at this point.
The client later calls display(). Noticing that no real image exists, the proxy builds one and loads the file. Every later call skips the loading step because the proxy keeps the real image in a field.
Common Mistakes
- Letting the proxy and the real class drift apart in method names. Both must implement the same interface.
- Stuffing business rules into a proxy. A proxy should guard, delay, or relay, and nothing more.
- Forgetting thread safety when two threads trigger the lazy load at the same moment.
Practice Idea
Write a protection proxy for a Document class. The proxy receives a user role in its constructor. Readers may call read(), and only editors may call edit(). Other roles receive a polite refusal message.
Key Takeaways
- A proxy shares the interface of the real object and guards it.
- Virtual, protection, remote, and caching proxies solve different needs.
- Clients stay unaware of whether they hold a proxy or the real object.
- Proxy controls access, while Decorator adds features.
