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.

🔑 Key line

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 USE
public:
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

  1. 01Intent — a stand-in with the same interface
  2. 02Virtual proxy — create the costly object lazily
  3. 03It forwards once access is allowed
  4. 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.

← Previous
Facade Pattern
Next →
Composite Pattern