design patterns · medium
Proxy Pattern
Proxy is a structural GoF pattern: a surrogate that implements the SAME interface as the real subject and stands in for it to control access — the client can't tell them apart. The most common form is the virtual proxy, which defers creating an expensive object until it's first used (ImageProxy stores only a filename and constructs the heavy RealImage on the first draw(), then delegates) — exactly how lazy thumbnails, ORM lazy-loading, and on-demand resources work. Other flavors: remote proxy (marshals calls to an object on another machine — RPC/gRPC stubs), protection proxy (checks permissions before forwarding), and smart-reference proxy (reference counting, logging, or caching — C++'s shared_ptr is exactly this). Proxy keeps the interface identical and governs WHEN/WHERE/IF/HOW-OFTEN the real object is accessed, distinguishing it from Adapter (which changes the interface) and Decorator (which adds behavior). The cost is an extra indirection layer and, for virtual proxies, a surprisingly slow first call that hides the construction.
Proxy (structural): a surrogate with the SAME interface as the real subject that controls access to it. Virtual proxy = lazy-create an expensive object on first use then delegate; other flavors are remote (network stub), protection (auth check), and smart-reference (refcount/cache — e.g. shared_ptr). Differs from Adapter (changes interface) and Decorator (adds behavior). Cost: a layer + hidden first-call latency.
The code
// Proxy — a stand-in with the SAME interface as the real object,// controlling access to it (lazy, remote, protect, cache, count).struct Image { virtual void draw() = 0; virtual ~Image() = default;};
class RealImage : public Image { // heavy: loads from disk std::string file_;
public: explicit RealImage(std::string f) : file_(std::move(f)) { load(); } void load() { /* expensive disk read */ } void draw() override { /* blit pixels */ }};
class ImageProxy : public Image { // virtual (lazy-load) proxy std::string file_; std::unique_ptr<RealImage> real_; // created ON FIRST USEpublic: explicit ImageProxy(std::string f) : file_(std::move(f)) {} void draw() override { if (!real_) real_ = std::make_unique<RealImage>(file_); // lazy real_->draw(); // then delegate }};What this lesson walks through
- 01Intent — a stand-in with the same interface
- 02Virtual proxy — create the costly object lazily
- 03It forwards once access is allowed
- 04Gotcha — transparency, lifetime, threading
A Proxy implements the SAME interface as the real object and stands in for it, so the client can't tell the difference. It intercepts each call to add control: lazy creation, access checks, caching, remoting, or ref-counting.
See it animated — step by step, at your own pace
Unlock the full interactive walkthrough of Proxy Pattern and 100+ animated C++ interview lessons.