ConceptDifficulty: Intermediate3 min

Proxy Pattern: A Stand-In That Controls Access to an Object

The caller thinks it holds the real object, and the stand-in decides whether, when and how to reach it.

The Proxy pattern places a stand-in object, the proxy, in front of a real object, with the same interface, so that every call from outside passes through the proxy first. The caller cannot tell the two apart, and the proxy decides whether a call reaches the real object, when, and how. This card covers the problems that call for one, the intent, and the four kinds of proxy.

The problems share a shape: access to an object needs control that the object should not hold itself. A high-resolution image takes seconds to load and may never be shown. A document store must check the user's role before a delete. A service runs on another machine. A rate lookup is slow and asked for repeatedly. Putting each of those concerns inside the object mixes it with the object's real job.

Access control inside the object, and in a stand-in

Without the patternthe real object checks its own callers

py
class DocumentStore:
    def delete(self, doc_id, user):
        if user.role != "editor":
            raise PermissionDenied(doc_id)
        del self._documents[doc_id]

Every method takes a user, and the store cannot be used without a permission model.

With the patternthe stand-in checks, the store stores

py
store = DatabaseDocumentStore()
documents = ProtectedDocumentStore(store, role)
documents.delete("plan")

The caller uses the same interface, and the permission check lives in one place.

The Gang of Four state the intent as: provide a surrogate or placeholder for another object to control access to it. The proxy holds, or knows how to reach, the real object, called the real subject, and passes on each call it allows.

The four kinds of proxy, by what each controls
KindWhat it controlsExample
VirtualWhen the real object is created: only on first useAn image loaded the first time it is drawn
ProtectionWhether a call is allowedA delete refused for a user without the editor role
RemoteWhere the real object is: the proxy forwards the call over the networkA client stub for a service on another machine
CachingWhether a repeated call reaches the real object at allA rate kept for a minute and returned from memory

Think of a receptionist who decides who gets through to the manager and when. The analogy breaks in one place: when the manager phones a colleague down the corridor, the call never passes the receptionist, and a real object calling its own methods skips its proxy in the same way.

Proxy is one of seven structural patterns, the family that composes classes and objects into larger structures.

The structural family, with this pattern marked
PatternWhat it does
AdapterGives an existing object the interface a client expects.
BridgeSeparates an abstraction from its implementation so both can vary.
CompositeTreats a tree of objects and a single object the same way.
DecoratorAdds behaviour by wrapping an object in another with the same interface.
FacadePuts one simple interface in front of a complex subsystem.
FlyweightShares the common part of many small objects to save memory.
Proxy (this topic)Stands in for an object to control access to it.
Proxy

Use it when

  • Creating the real object is costly and it may never be used.
  • Calls need a check, a cache or a network hop that the real object should not know about.
  • The caller must keep using the same interface, unaware of the control in front of it.

Avoid it when

  • The control is needed by the object's own internal calls, which a proxy never sees.
  • The goal is to add features that stack, which is Decorator.
  • The extra layer would hide a cost, such as a network call, that the caller needs to know about.