Decorator and Proxy have almost identical structure — both wrap an object behind the same interface. How do you tell them apart, and how do both differ from Adapter?
answer
- same shape, different intent
- Decorator adds; Proxy governs access
- Adapter changes the interface
- proxy usually owns/creates the subject
- decorators stack; proxies usually do not
basics
~20 sDecorator adds extra behavior to an object; Proxy controls access to it (lazy creation, remote calls, permission checks, lifecycle). Both keep the interface. Adapter is different again: it changes one interface into another so incompatible code can work together.
solid answer
~50 sAll three are wrappers; the difference is intent, not shape. **Decorator** adds responsibilities. The wrapped object is handed to it from outside, it always represents an existing object, and decorators are designed to be stacked in varying combinations chosen at runtime. **Proxy** controls access to a subject. Typical variants: virtual (create the expensive object only on first use), remote (the real object lives elsewhere), protection (authorization checks), smart reference (reference counting, locking, lazy loading of ORM associations). A proxy usually *owns or creates* the subject rather than receiving it, and there is normally one proxy, not a stack. The client often does not even know a proxy exists. **Adapter** converts an interface: the client expects `Target`, the existing class offers `Adaptee`, and the adapter translates. It deliberately does *not* preserve the interface — that is its whole point. Rule of thumb: same interface + more behavior = Decorator; same interface + gate/indirection = Proxy; different interface = Adapter.
go deeper
State the one-liners: Decorator adds behavior, Proxy controls access, Adapter changes the interface — with one example each.
Explain that structure is identical for Decorator and Proxy and that intent decides, then name proxy variants (virtual, remote, protection, smart reference) and give the stacking difference.
Handle the grey areas honestly (caching, framework-generated proxies), relate to Composite/Chain of Responsibility/Strategy, and note that both proxies and decorators miss self-calls.
Discuss when to stop hand-writing wrappers and adopt generated proxies or an interceptor pipeline, and the governance cost of implicit framework proxies versus explicit, readable decoration.
## Why the confusion exists Decorator, Proxy, Adapter (object form), and to a lesser degree Composite and Chain of Responsibility all use the same mechanism: an object holding a reference to another object and forwarding calls. Structural diagrams for Decorator and Proxy are essentially identical. The Gang of Four classify patterns by **intent**, not by class diagram — so the discriminating question is always *why does the wrapper exist?* ## Decorator: add responsibilities - **Intent:** attach additional behavior to an individual object dynamically. - **Interface:** identical to the wrapped type (transparency is required). - **Wrappee:** supplied by the caller/wiring code; the decorator does not decide what it wraps. - **Cardinality:** built to stack — `metrics(cache(retry(real)))` — and combinations vary per environment. - **Examples:** buffering/compressing/encrypting stream wrappers; adding logging, caching, retries, or metrics to a service; adding scrollbars or borders to a UI widget; wrapping a collection to make it read-only or synchronized. ## Proxy: control access - **Intent:** provide a surrogate or placeholder that controls access to another object. - **Interface:** also identical — but the extra code is about *whether, when, and where* the real call happens, not about enriching the result. - **Subject:** typically created, located, or lifecycle-managed by the proxy itself; often the client cannot supply it. - **Cardinality:** normally one proxy, not a configurable stack. - **Canonical variants:** - *Virtual proxy* — defers construction of an expensive object until first use (lazy-loaded ORM associations, image placeholders). - *Remote proxy* — local stand-in for an object in another process or machine; hides marshalling and network calls (RPC/RMI client stubs). - *Protection proxy* — enforces permissions before forwarding. - *Smart reference* — reference counting, locking, copy-on-write, usage tracking. ## Adapter: convert the interface - **Intent:** make an existing class usable through an interface the client already expects. - **Interface:** deliberately *different* from the adaptee's. The adapter implements `Target` while holding (object adapter) or inheriting (class adapter) the `Adaptee`. - **Cardinality:** one adapter per mismatched pair; adapters are not stacked for effect. - **Examples:** wrapping a third-party payment SDK behind your own `PaymentGateway` interface; making a legacy `enumerate()` API satisfy a modern iterator contract. ## Quick discriminator | Question | Decorator | Proxy | Adapter | |---|---|---|---| | Does the wrapper expose the same interface? | yes | yes | no | | Is the point to *add* capability? | yes | no | no | | Is the point to *govern/relocate/defer* access? | no | yes | no | | Is the point to *translate* a contract? | no | no | yes | | Designed to stack in varying combos? | yes | rarely | no | | Who supplies the wrapped object? | the client/wiring | usually the wrapper itself | the client | ## Nearby relatives - **Composite** — same recursive shape but holds *many* children and models a part–whole tree; Decorator holds exactly one and adds behavior. A decorator can be described as a degenerate composite with a single child and added responsibility. - **Chain of Responsibility** — a chain of handlers where a handler may *stop* the chain and where the intent is to find a handler; decorators normally all participate and preserve the operation. - **Facade** — one simplified entry point over a whole subsystem, not a same-interface wrapper over one object. - **Strategy** — swaps an algorithm *inside* an object rather than layering behavior *around* it; it changes the guts, not the skin. - **Middleware/interceptor pipelines** — the same idea generalized: a linear chain of same-signature handlers around a core, typically configured centrally. ## Grey areas (and how to answer them well) A caching wrapper is arguably both: it adds a capability *and* prevents access to the real object. A logging wrapper that also enforces a rate limit blurs the line too. The honest interview answer is: the structure is one mechanism, the labels record intent, and in a code review what matters is that each wrapper has a single clear purpose and that the interface remains substitutable. Say which intent dominates and why, rather than insisting on a rigid taxonomy. One more practical distinction: many frameworks generate proxies automatically (dynamic proxies, bytecode subclasses) to implement transactions, security, and caching. Because these are generated, self-calls inside the target object bypass them — the same limitation decorators have, since both only intercept calls that cross the object boundary.
- Is a lazy-loading wrapper a Decorator or a Proxy?A Proxy — specifically a virtual proxy. Its purpose is to defer creation and control when the real object is touched, not to enrich the operation. The give-away is that it creates the subject itself rather than being handed one.
- Both Decorator and Composite hold references of the component type. What single check separates them?Cardinality plus intent: Composite holds a collection of children and aggregates them into a part–whole tree; Decorator holds exactly one wrappee and adds responsibility to it.
- Can Decorator and Adapter appear in the same stack?Yes and it is common: adapt a third-party client to your interface, then decorate the adapted object with retry and metrics. The adapter sits innermost, closest to the foreign library.
A Decorator is a phone case: same phone, same buttons, extra protection, and you can add a grip on top of it. A Proxy is a receptionist: the same conversation, but she decides whether you get through, or reaches the person in another building for you. An Adapter is a travel plug: it does not add anything, it just makes an incompatible connector fit.
saying these in an interview costs you the question
- "Decorator and Proxy are the same pattern with different names" — the structure matches but the intent, ownership, and stacking differ.
- "Adapter adds functionality" — it translates a contract; adding behavior is not its job.
- Using UML shape alone to classify a wrapper.
- "A proxy must be on a different machine" — remote is only one of several proxy variants.
- "Decorator changes the interface so callers can use new methods" — added public methods are invisible through the shared interface and defeat transparency.
- Calling a Facade a Decorator because both wrap things — a Facade simplifies a whole subsystem behind a new, narrower interface.