Proxy Pattern

Intent
Problem
- A service object is resource-intensive (e.g., a video downloader)?
- You want lazy loading, access control, or caching?
- You can’t change the service class (e.g., it’s from a 3rd-party library)?
Solution
- Lazy initialization
- Logging
- Caching
- Access control
- Remote interaction (RPC)
Real-World Analogy
Structure
- Service Interface: Defines operations
- Real Service: Implements core logic
- Proxy: Implements the same interface and controls access
- Client: Talks only to the interface
Example (JavaScript-Inspired Pseudocode)
Javascript
// Service interface
class YouTubeService {
listVideos() {}
getVideoInfo(id) {}
downloadVideo(id) {}
}
// Real service implementation (e.g., 3rd-party)
class RealYouTubeService extends YouTubeService {
listVideos() {
console.log("Fetching videos from YouTube...");
return ["video1", "video2"];
}
getVideoInfo(id) {
console.log(`Fetching info for video ${id}...`);
return { id, title: `Video ${id}` };
}
downloadVideo(id) {
console.log(`Downloading video ${id}...`);
}
}
// Proxy with caching
class CachedYouTubeProxy extends YouTubeService {
constructor(realService) {
super();
this.service = realService;
this.videoListCache = null;
this.videoInfoCache = {};
}
listVideos() {
if (!this.videoListCache) {
this.videoListCache = this.service.listVideos();
}
return this.videoListCache;
}
getVideoInfo(id) {
if (!this.videoInfoCache[id]) {
this.videoInfoCache[id] = this.service.getVideoInfo(id);
}
return this.videoInfoCache[id];
}
downloadVideo(id) {
this.service.downloadVideo(id);
}
}
// Client
const service = new CachedYouTubeProxy(new RealYouTubeService());
service.listVideos(); // Fetches from real YouTube
service.listVideos(); // Returns cached result
service.getVideoInfo("v1"); // Fetches and caches info
service.getVideoInfo("v1"); // Returns cached info
service.downloadVideo("v1"); // Always delegates to real service
When to Use
- Lazy loading: Defer creation of heavy objects
- Access control: Restrict access to sensitive data
- Caching: Avoid redundant network or computation
- Remote access: Act as local rep for remote service (RPC)
- Smart references: Track access or usage
Pros & Cons
- Controls access transparently
- Adds behavior without modifying original object
- Supports Open/Closed Principle (can extend functionality easily)
- More classes = more complexity
- Potential latency due to indirect access
- Harder to debug when proxies get deep