How do you tell Proxy and Decorator apart, given they are structurally almost identical in Java?
answer
- Same structure, different intent
- Decorator = add behavior, stacked, given the object
- Proxy = control access, transparent, often owns the subject
- Adapter = different interface (the third sibling)
- Test: changes WHAT it does (decorator) vs HOW you reach it (proxy)
basics
~20 sBoth wrap an object of the same interface and forward calls. The difference is intent: a Decorator adds new behavior and is meant to be stacked, while a Proxy controls access (lazy creation, permissions, remoting) and is meant to be invisible to the caller.
solid answer
~50 sProxy and Decorator share the same structure: a wrapper that implements the target's interface and delegates to a wrapped instance. The distinction is intent and lifecycle. A Decorator's job is to add or augment behavior — you knowingly compose several (BufferedInputStream over GZIPInputStream over FileInputStream) and each adds a responsibility. A Proxy's job is to control access to its subject: it decides whether, when, or where the real call happens (lazy creation in a virtual proxy, permission checks in a protection proxy, network marshaling in a remote proxy). A proxy is meant to be transparent and often owns or creates the single real subject's lifecycle, whereas a decorator is given an already-existing component to enrich and clients deliberately build the chain. Rule of thumb: if the wrapper changes *what the object does*, it's a decorator; if it changes *how/whether you reach the object*, it's a proxy.
go deeper
Can say both wrap an object and that one adds behavior while the other controls access, even if examples are shaky.
Gives the intent-based distinction with concrete Java examples (java.io decorators, Spring/Hibernate proxies) and brings in Adapter as the interface-changing sibling.
Articulates the decision test crisply, handles boundary cases like synchronizedList, and maps each pattern to real JDK/framework usage with lifecycle reasoning.
Discusses why GoF separates by intent not structure, the design consequences of transparency vs explicit composition, and how to communicate intent in a codebase so the wrapper's role is unambiguous to maintainers.
## Why this is confusing In Java code, a Proxy and a Decorator look the same: a class that **implements the same interface** as the thing it wraps, holds a reference to that thing, and **forwards** method calls to it, optionally doing work around the call. Because the *mechanism* (interface-sharing + delegation) is identical, the GoF themselves separate these patterns purely by **intent**, not structure. ## Decorator — add behavior - **Intent:** attach **additional responsibilities** to an object dynamically. The wrapper's whole reason to exist is to do *more* than the wrapped object — buffer, compress, encrypt, add a scrollbar. - **Composition:** decorators are designed to be **stacked**; clients knowingly build the chain and order matters. The canonical Java example is `java.io`: `new BufferedReader(new InputStreamReader(new FileInputStream(f)))` — each layer adds a capability. - **Lifecycle:** a decorator is *handed* a fully-formed component to enrich; it does not own whether that component exists. - **Visibility:** the client is fully aware it is composing behaviors. ## Proxy — control access - **Intent:** provide a **surrogate that controls access** to the subject. The wrapper exists to govern *whether, when, where, and for whom* a call reaches the real object — not to add domain behavior. - **Kinds:** virtual (create lazily), protection (permission check), remote (marshal across a boundary), smart (logging/ref-counting/caching). - **Lifecycle:** a proxy frequently **owns or creates** the single real subject (a virtual proxy may construct it on first use, a remote proxy may stand in for an object that doesn't even exist locally). - **Visibility:** a proxy is meant to be **transparent** — ideally the client never knows it isn't talking to the real thing. ## A decision test Ask *what changes*: - The wrapper makes the object **do more / different domain work** → **Decorator**. - The wrapper changes **whether/when/where/by-whom** you reach the object, with the object's own behavior unchanged → **Proxy**. Also ask about **count and stacking**: many cooperating wrappers each adding a feature → decorator; a single guardian around one subject → proxy. ## And don't confuse either with Adapter **Adapter** also wraps and delegates, but it **changes the interface** — it makes an incompatible type usable where a different interface is expected (`Arrays.asList`, `InputStreamReader` viewed as interface conversion byte→char). Proxy and Decorator both **keep the same interface**; Adapter deliberately presents a *different* one. So the three split cleanly: - **Adapter** → same object, **different interface** (compatibility). - **Decorator** → same interface, **more behavior** (enhancement). - **Proxy** → same interface, **controlled access** (governance). ## In real Java - Decorator: `java.io` streams/readers, `Collections.synchronizedList`/`unmodifiableList` (these wrap to add synchronization / immutability behavior). - Proxy: Spring AOP proxies for `@Transactional`/`@Secured`, Hibernate lazy-loaded entity proxies (virtual), RMI stubs (remote), mock objects. A subtle case: `Collections.synchronizedList` and `unmodifiableList` are usually classified as **decorators** because they *change behavior* (thread-safety, write-rejection) rather than govern access/existence — though they sit close to the boundary, which is exactly why interviewers like the question.
- Is Collections.synchronizedList a proxy or a decorator?It's generally classified as a decorator: it wraps a list of the same interface and adds new behavior (synchronization on every operation) rather than governing access to or the existence of the underlying list. It sits near the boundary, which is why it's a good discussion point.
- Where does Adapter fit relative to these two?Adapter also wraps and delegates but deliberately exposes a *different* interface to make an incompatible type usable. Proxy and Decorator both preserve the original interface; Adapter changes it for compatibility.
saying these in an interview costs you the question
- Saying they differ structurally — they are structurally the same; intent is the differentiator
- Calling a permission-check or lazy-load wrapper a decorator
- Lumping Adapter in — Adapter changes the interface, the other two keep it
- Claiming a proxy never owns the target's lifecycle (a virtual proxy creates it)