โ Back to Design Patterns
๐ช
Structural
Proxy
Provides a placeholder that controls access to another object โ adding lazy loading, caching, or access checks.
The Problem
A heavyweight object (network call, database, large file) should not be created or accessed until absolutely needed. You want to add access control or caching without touching the original class.
How It Works
- โบClient talks to the proxy through the same interface as the real object
- โบVirtual proxy: defers expensive creation until first use (lazy initialization)
- โบCaching proxy: remembers results and returns cached copies
- โบProtection proxy: checks permissions before delegating
- โบRemote proxy: represents an object in a different address space
When to Use
โLazy initialization of a resource-heavy object
โCaching to avoid repeated expensive operations
โAccess control โ verify permissions before allowing an operation
โLogging or monitoring access to a sensitive object
Real-World Examples
๐
iOS
lazy var properties, SDWebImage lazy image loading, CoreData faulting
๐ค
Android
by lazy delegate, Glide placeholder images, ViewModel lazy init
๐
Web
ES6 Proxy, service workers as network proxies, memoization helpers
Code Examples
Swift
protocol ImageLoader {
func load(url: String) -> String
}
class RealImageLoader: ImageLoader {
func load(url: String) -> String {
print("Network: loading \(url)")
return "ImageData(\(url))"
}
}
// Caching proxy
class ImageLoaderProxy: ImageLoader {
private let real = RealImageLoader()
private var cache = [String: String]()
func load(url: String) -> String {
if let cached = cache[url] { print("Cache hit"); return cached }
let data = real.load(url: url)
cache[url] = data
return data
}
}
let loader: ImageLoader = ImageLoaderProxy()
loader.load(url: "https://example.com/photo.jpg") // Network load
loader.load(url: "https://example.com/photo.jpg") // Cache hit