How does Bridge differ from Adapter, especially in terms of when each is introduced into a Java codebase?
answer
- Adapter = retrofit/after the fact; Bridge = up-front design
- Adapter joins interfaces designed apart; Bridge designs them together
- Adapter wraps a third-party/legacy Adaptee
- Both delegate through an interface — intent differs, not shape
- JDBC/AWT peers = Bridge; InputStreamReader/Arrays.asList = Adapter
basics
~20 sAdapter makes an existing class with the 'wrong' interface fit something you already have — it's added after the fact to bridge a mismatch. Bridge is planned from the start to keep an abstraction and its implementation separate so both can grow independently.
solid answer
~50 sThey look structurally similar — both put an object behind an interface and delegate to it — but their intent and timing differ. Adapter is a *retrofit*: you have an existing, often third-party, class whose interface doesn't match what your code expects, so you wrap it to translate one interface into another. It's reactive, introduced after the mismatch appears, and the two interfaces it joins were designed by different people who never coordinated. Bridge is *designed up front*: before writing the classes you anticipate two independent axes of variation and deliberately split them into an abstraction hierarchy and an implementation hierarchy that evolve in parallel. Bridge's two interfaces are designed together to fit; Adapter's are designed apart and forced to fit. Mnemonic: Adapter says 'make these two existing things work together'; Bridge says 'keep these two things separate so they can each change freely'.
code
java · 22 lines// ADAPTER (retrofit): foreign class doesn't match the interface we expect.
interface MediaPlayer { void play(String file); } // Target our code expects
class LegacyAudioEngine { // Adaptee (can't change it)
void start(String path) { /* ...vendor code... */ }
}
class LegacyPlayerAdapter implements MediaPlayer { // wrap + translate
private final LegacyAudioEngine engine = new LegacyAudioEngine();
public void play(String file) { engine.start(file); } // adapt method names
}
// BRIDGE (up-front): two hierarchies designed together to vary independently.
interface Renderer { void renderText(String s); } // Implementor
abstract class View { // Abstraction
protected final Renderer renderer; // the bridge
protected View(Renderer r) { this.renderer = r; }
abstract void show();
}
class Alert extends View {
private final String msg;
Alert(String msg, Renderer r) { super(r); this.msg = msg; }
void show() { renderer.renderText("ALERT: " + msg); }
}go deeper
Can state the headline: Adapter fixes a mismatch after the fact; Bridge is planned ahead to keep two things separate.
Can describe Adaptee/Target for Adapter and abstraction/implementor for Bridge, and give at least one JDK example of each.
Explains that the patterns share structure but differ in intent and timing, names the 'designed apart vs designed together' distinction, and reasons about which to apply in a real scenario.
Discusses how the same delegating structure serves opposite goals, ties Bridge to ports-and-adapters/hexagonal layering, and warns against pattern-name bikeshedding when the structure is what's shipped.
## Why this comparison matters Bridge and Adapter are both **structural** patterns and they share a skeleton: an object that holds another object behind an interface and forwards (delegates) calls to it. Because the UML diagrams look almost identical, interviewers love asking how they differ. The real difference is **intent and timing**, not shape. ## Adapter — the retrofit An **Adapter** converts the interface of an existing class into another interface the client expects. The textbook situation: you have working code that talks to an interface `Target`, and you want to reuse an existing class `Adaptee` whose methods have different names/signatures — often a **third-party library** you can't modify. You write an `Adapter` that *implements* `Target` and internally holds an `Adaptee`, translating each `Target` call into the appropriate `Adaptee` call. Key properties: - **Reactive / after the fact.** It's introduced *because* an incompatibility already exists. Nobody plans an adapter before the mismatch. - **The two sides were designed independently** — different authors, no coordination. The adapter's whole job is to bridge that accidental gap. - **One-sided.** You usually adapt to make a specific existing API usable; you're not setting up two parallel hierarchies to vary forever. ## Bridge — the up-front design A **Bridge** decouples an abstraction from its implementation so both can vary independently (see the intent question). Key properties: - **Proactive / designed up front.** You foresee two axes of variation and split them *before* the classes exist, so growth on each axis is cheap. - **The two interfaces are designed together to fit.** The abstraction's needs shape the implementor interface and vice versa — they cooperate by design. - **Two-sided, open-ended.** Both hierarchies are expected to keep gaining members. ## Side-by-side | Aspect | Adapter | Bridge | |---|---|---| | Intent | Make an existing 'wrong' interface usable | Let abstraction and implementation vary independently | | Timing | Retrofit, after a mismatch appears | Designed up front | | Interfaces | Designed apart, forced to fit | Designed together to fit | | Typical trigger | Reusing a third-party/legacy class | Foreseeing two variation axes | | Direction of growth | Usually one fixed integration | Both hierarchies keep growing | ## How they appear in Java code - An **Adapter** is typically a small class named `XyzAdapter` that `implements SomeExpectedInterface` and holds the foreign object — e.g. `java.io.InputStreamReader` adapts a byte `InputStream` to a character `Reader`; `java.util.Arrays.asList` adapts an array to the `List` interface. - A **Bridge** shows up as paired hierarchies wired in a constructor — e.g. the JDBC design, where your code uses the `java.sql.*` abstraction and a vendor `Driver`/implementation is plugged in behind it. The AWT peer architecture (a `Component` delegating to a platform `ComponentPeer`) is the canonical JDK Bridge. ## Defined terms - **Adaptee**: the existing class with the incompatible interface that an Adapter wraps. - **Target**: the interface the client already expects; an Adapter implements it. - **Retrofit**: adding something after the fact to fix an existing situation. - **Axis of variation**: an independent dimension along which a design is expected to change (e.g. shape vs renderer). ## The one-line answer Both delegate through an interface; the difference is *intent and timing*: **Adapter retrofits two things that were already designed apart; Bridge is designed in advance to keep two things apart so they can vary independently.**
- Give a JDK example of each.Adapter: java.io.InputStreamReader adapts a byte InputStream to a character Reader; Arrays.asList adapts an array to List. Bridge: the AWT Component-to-ComponentPeer design, and arguably the JDBC API-vs-Driver split.
- If two interfaces look identical in code, how do you decide which pattern you're looking at?Ask why it exists. If it was added to make an existing mismatched class usable, it's an Adapter. If both interfaces were designed together to let two dimensions vary independently, it's a Bridge.
saying these in an interview costs you the question
- Saying they're interchangeable because the UML looks the same — the differentiator is intent and timing
- Claiming Adapter is always added up front
- Saying Bridge is for fixing incompatible third-party APIs (that's Adapter)
- Asserting Bridge uses inheritance to combine the two sides