How does the Facade pattern differ from Adapter and Proxy, and why does the distinction matter when reading JDK APIs?
answer
- Same shape, different intent
- Facade=simplify many, Adapter=convert one, Proxy=gate one
- InputStreamReader = Adapter; Files = Facade
- Proxy keeps SAME interface; Adapter CHANGES it
- java.lang.reflect.Proxy / RMI stubs
basics
~20 sFacade simplifies a complex subsystem behind one easy interface. Adapter changes one class's interface into a different one the caller expects. Proxy stands in for an object to control access (lazy, remote, security). All three wrap something, but for different reasons.
solid answer
~50 sAll three are structural patterns that wrap other objects, so people confuse them. The deciding factor is *intent*. Facade exists to *simplify*: it puts one convenient entry point over a whole subsystem of cooperating classes (e.g. java.nio.file.Files over channels/charsets/buffers); the subsystem stays directly usable and the facade adds no new behavior. Adapter exists to *convert*: it makes one existing interface look like a different, incompatible one the client requires — e.g. java.io.InputStreamReader adapting a byte InputStream into a character Reader. Proxy exists to *control or defer access* to a single target object while keeping the same interface — lazy initialization, remote calls (RMI stubs), or access checks (java.lang.reflect.Proxy for dynamic interception). So: Facade = many-to-one simplification, Adapter = interface translation, Proxy = same-interface gatekeeper. Reading JDK source, this lets you predict what a wrapper does just from why it exists.
go deeper
Can state that all three wrap other objects and give a one-line intent for each.
Correctly maps each pattern to a JDK example (Files=Facade, InputStreamReader=Adapter, reflect.Proxy=Proxy) and explains the intent distinction.
Articulates many-to-one vs one-to-one, same-interface vs different-interface, and folds in Decorator to complete the comparison.
Reasons about how a library should layer these (capability subsystem + adapters + facade) and the API-evolution consequences of each choice.
## Why this comparison comes up Facade, Adapter, and Proxy are all **structural** Gang-of-Four patterns, meaning they all describe ways to compose objects so that one object *wraps* or stands in front of another. Because the mechanical shape is similar (object A holds a reference to object(s) B and forwards calls), beginners lump them together. The patterns are distinguished not by *shape* but by **intent** — the reason the wrapper exists. Knowing the intent lets you read an unfamiliar JDK class and immediately guess its role. ## Facade — simplify a subsystem A *subsystem* is a group of cooperating classes that together perform real work (in NIO: `FileChannel`, `ByteBuffer`, `Charset`, `Path`, `FileSystem`). A **Facade** is a single higher-level object that offers a simple interface to that whole group, doing the multi-step orchestration internally. Defining traits: - **Many-to-one:** it sits over *several* classes, not just one. - **Simplifies, does not restrict:** the subsystem classes remain public; you can bypass the facade for advanced control. - **Adds no new capability** of its own — it only re-packages existing behavior into an easy default path. - JDK example: `java.nio.file.Files`, `java.net.http.HttpClient`. ## Adapter — convert an interface An **Adapter** wraps *one* existing object whose interface is incompatible with what the client needs, and translates calls so the client can use it. The point is *interface compatibility*, not simplification. - **One-to-one translation:** old interface in, expected interface out. - The wrapped object's capability is unchanged; only the *shape* of the API changes. - JDK examples: `java.io.InputStreamReader` adapts a byte-oriented `InputStream` into a character-oriented `Reader`; `java.util.Arrays.asList(...)` adapts an array into a `List` view; `java.util.Collections.list(Enumeration)` adapts the legacy `Enumeration` API toward `Iterator`/`List` usage. ## Proxy — control access to one target A **Proxy** wraps a *single* target object and exposes the **same interface** as that target, inserting itself in front to control or defer access. The client cannot tell it is talking to a proxy. Common reasons: - **Virtual proxy** — lazily create/load the expensive real object on first use. - **Remote proxy** — the target lives in another JVM/machine (RMI stubs). - **Protection proxy** — perform access/security checks before forwarding. - JDK examples: `java.lang.reflect.Proxy` (dynamic proxies that route every interface call to an `InvocationHandler`), RMI stubs. ## The cheat-sheet | Pattern | Wraps | Interface vs target | Intent | |---|---|---|---| | Facade | a whole subsystem (many) | a *new, simpler* interface | simplify / reduce coupling | | Adapter | one object | a *different* interface the client needs | convert incompatible APIs | | Proxy | one object | the *same* interface as the target | control/defer access | ## Why it matters in the JDK The Java standard library is a giant catalogue of these patterns. When you encounter `Files`, recognizing it as a facade tells you "this is the easy path; the granular `FileChannel` API is underneath for control." When you see `InputStreamReader`, recognizing Adapter tells you "this bridges bytes to chars; it doesn't add buffering — that's `BufferedReader` (a decorator) on top." When you see a `$Proxy0` class at runtime, recognizing Proxy tells you a dynamic proxy is intercepting interface calls. The patterns are a vocabulary that makes unfamiliar APIs predictable. ## Common confusions to avoid - Facade *can* technically present a different interface than any single subsystem class, but its goal is simplification of *many*, whereas Adapter's goal is matching *one* required interface — judge by intent, not just by whether the signature changed. - A decorator (e.g. `BufferedReader` wrapping a `Reader`) keeps the same interface but *adds behavior* — that is yet another pattern (Decorator), distinct from Proxy (same interface, controls access, adds no domain behavior).
- Is InputStreamReader a facade?No — it adapts one byte InputStream into a character Reader (interface conversion), so it is an Adapter. A facade simplifies a whole subsystem of multiple classes.
- How does a Decorator differ from a Proxy, since both keep the same interface?A Decorator adds new behavior/responsibility (e.g. BufferedReader adds buffering), while a Proxy adds access control or deferral (lazy/remote/security) without changing the domain behavior.
saying these in an interview costs you the question
- Calling Adapter a Facade because both 'wrap' something — intent differs (convert vs simplify).
- Saying a Proxy presents a different interface — a Proxy keeps the SAME interface as its target.
- Treating these as defined by code shape rather than by intent.