SwadhyAI Notes

All Low-Level Design notes

Structural · two axes, not a wrap of a vendor

Bridge

A is a structural pattern that separates two independent hierarchies so each can grow without creating a new class for every combination. One hierarchy is the high-level API; the other is the platform or mechanism it talks to.

A concrete failure mode: a drawing app starts with Circle and Square, then red and blue, then “draw on screen” and “print on a plotter.” CircleRedScreen, CircleRedPlotter, SquareBlueScreen… the class list becomes a multiplication table. That mess is a . Bridge is the fix.

The multiplication table you should refuse to write

Remote features × device types. Every cell is a class. Add one device, and you double the rows. Use Bridge when you can already see this table — not merely because “I wrapped something.”

BasicAdvanced
TvBasicTvRemoteAdvancedTvRemote
RadioBasicRadioRemoteAdvancedRadioRemote
StickBasicStickRemoteAdvancedStickRemote

6 classes for 2 × 3. The next feature makes it 8. Stop and split the axes.

Split into N + M, not N × M

— how we talk

  • Remote — togglePower
  • AdvancedRemote — mute

— what we talk to

  • Tv — turnOn, setVolume
  • Radio — turnOn, setVolume

Remote holds a Device. AdvancedRemote.mute() calls device.setVolume(0). You never write AdvancedTvRemote. Name the first. If you cannot, you do not need Bridge.

Diagram text: the exact Mermaid definition below preserves the nodes, labels, and connections. Enable JavaScript to view the rendered diagram.
Read the diagram definition
flowchart LR
  subgraph abs [Abstraction]
    R[Remote]
    B[BasicRemote]
    A[AdvancedRemote]
    B --> R
    A --> R
  end
  subgraph impl [Implementor]
    D[Device]
    T[Tv]
    Radio[Radio]
    T --> D
    Radio --> D
  end
  R -->|holds| D

Core question

Do I have two independent axes of change that will explode if I subclass both?

Java sketch: Remote × device, not RemoteTv subclasses

Tv Radio same remotes
java
interface Device {
  void turnOn();
  void turnOff();
  void setVolume(int level);
}

class Tv implements Device { /* hardware calls */ }
class Radio implements Device { /* hardware calls */ }

class Remote {
  protected final Device device;
  Remote(Device device) { this.device = device; }
  void togglePower() { device.turnOn(); }
}

class AdvancedRemote extends Remote {
  AdvancedRemote(Device device) { super(device); }
  void mute() { device.setVolume(0); }
}

// new AdvancedRemote(new Tv())  — not AdvancedTvRemote

Shape × color — the same split

Circle does not subclass into CircleRed. Circle holds a Color. A new shape is one class. A new paint is one class. You do not need a class per pair.

java
interface Color {
  String hex();
}

class Red implements Color {
  public String hex() { return "#FF0000"; }
}

abstract class Shape {
  protected final Color color;
  Shape(Color color) { this.color = color; }
  abstract void draw();
}

class Circle extends Shape {
  Circle(Color color) { super(color); }
  void draw() { /* stroke a circle in color.hex() */ }
}

Machine-coding cousin: Document × Store

“Remote vs local” in interviews is the same move. A high-level operation holds a LocalStore or a RemoteStore. The save/load code does not fork. Cache, Queue, and Notification (severity × channel) are the same two-axis picture.

java
interface Store {
  void put(String id, byte[] body);
  byte[] get(String id);
}

class LocalDiskStore implements Store { /* files */ }
class RemoteHttpStore implements Store { /* network */ }

class Document {
  private final Store store;
  Document(Store store) { this.store = store; }
  void save(String id, byte[] body) { store.put(id, body); }
}

class VersionedDocument extends Document {
  VersionedDocument(Store store) { super(store); }
  void saveVersioned(String id, byte[] body, int rev) {
    save(id + "@" + rev, body);
  }
}

Bridge is not Adapter, Strategy, or a random wrap

vs Adapter

Adapter appears when a class already exists and will not match your interface. Bridge appears when you plan two hierarchies. Same word “wrap,” different timing and different problem.

vs Strategy

Strategy varies one algorithm (pricing, allocation) under a single context. Bridge varies a whole implementation hierarchy under a whole abstraction hierarchy. If only one axis moves, Strategy is enough.

vs Facade

Facade hides many classes behind one method. Bridge does not hide a subsystem; it decouples two dimensions so they can grow. Clients still see Remote and Device.

How to implement it (four steps)

  1. 01

    Name the two axes

    Shape vs color. Remote vs device. Document vs storage. If you cannot name two, stop.

  2. 02

    Put one axis behind an interface

    Device, DrawingApi, Color, Store — the part the other axis will call.

  3. 03

    Hold it in the abstraction

    Remote has a Device. Inject it. Do not new Tv inside every Remote subclass.

  4. 04

    Grow each side alone

    Add AdvancedRemote without touching Tv. Add Radio without touching Remote.

Common mistakes

Calling Adapter a Bridge

Adapter is after the fact for one foreign type. Bridge is designed because two dimensions will multiply. Do not rename StripePayableAdapter to StripeBridge.

A Bridge for a single axis

If only pricing changes, Strategy is enough. An extra DrawingApi with one implementation is ceremony. Wait until you can name the second axis out loud.

new Tv() inside BasicRemote

If the abstraction constructs the implementor, the sides are glued again. Inject Device. Tests pass a fake Device.

How to explain this in an interview

“I see two axes — remote features and device types — so I will Bridge: Remote holds Device. I will not subclass AdvancedTvRemote. This is not an adapter; both hierarchies are ours.”
  1. Count classes for 3 remotes × 4 devices without Bridge, then with Bridge.
  2. Notification severity × Email/SMS/Push. Is that Bridge, Strategy, or both? Defend the split.

Takeaway

Use Bridge when you can already see a multiplication table of subclasses. Split the axes, inject one into the other, and grow each side alone. Do not use Bridge as a fancy name for Adapter.