One foreign type
Adapter
Adapter changes the method shape of one existing class so it matches an interface you already use. Example: StripeClient cannot be Payable until a small translator maps cents and charge ids.
Full Adapter pageMany familiar types
Facade
Facade gives one simple method in front of several classes you already own. Inventory, Payable, Invoice, and Mailer already speak fine — the caller should not have to orchestrate all of them.
Full Facade pageIf you call both “a wrapper,” you will pick the wrong one in an interview.
One sentence
Am I changing one foreign interface to match mine, or hiding many classes behind one friendly method?
changes a foreign interface to match yours. keeps the existing interfaces and hides many classes behind one friendly method.
Same checkout, two different objects
Adapter · change shape
StripeClient.charge(token, cents) cannot be Payable.pay(Money, orderId) until a translator sits in the middle. After the adapter, you still have one collaborator — it just speaks your language. This means the number of objects did not go down. Only the shape of the call changed.
Facade · reduce count
Inventory, Payable, InvoiceService, and Mailer already have fine APIs. The pain is that every controller must remember the sequence. CheckoutFacade.placeOrder does not rename those APIs. It stops the rest of the app from calling them directly.
Decision grid — fill this on the whiteboard
| Ask | Adapter | Facade |
|---|---|---|
| How many types sit behind the wrap? | One foreign class | Several familiar classes |
| What changes? | Method names, argument types, return types | How many collaborators the caller must know |
| Do the inner APIs stay? | No — they cannot be your interface without mapping | Yes — Inventory is still Inventory |
| After the wrap, collaborator count | Still one | Dropped from many to one entry point |
| Typical smell | charge(token, cents) is not pay(Money, id) | Controller calls reserve, pay, invoice, mail |
| Wrong name in interviews | Calling a four-service door an Adapter | Calling a Stripe rename a Facade |
Adapter: one class, wrong shape
class LegacyPrinter { void output(byte[] raw) { } }
interface ReceiptPrinter {
void print(Receipt receipt);
}
class LegacyReceiptAdapter implements ReceiptPrinter {
private final LegacyPrinter legacy;
public void print(Receipt receipt) {
legacy.output(receipt.toBytes());
}
}Facade: many classes, one door
class HotelFrontDesk {
private final Reservations rooms;
private final Billing billing;
private final Housekeeping housekeeping;
KeyCard checkIn(Guest guest, Dates stay) {
Room room = rooms.allocate(stay);
billing.openFolio(guest, room);
housekeeping.prepare(room);
return room.keyCard();
}
}They compose. They are not synonyms.
A facade may hold an adapter: placeOrder talks to Payable, and Payable happens to be StripePayableAdapter. That is healthy. What is not healthy is using Adapter when the smell is “too many collaborators,” or Facade when the smell is “wrong method names on one SDK.”
class CheckoutFacade {
private final Inventory inventory;
private final Payable payment; // often a StripePayableAdapter
private final InvoiceService invoices;
private final Mailer mailer;
Receipt placeOrder(Cart cart) {
inventory.reserve(cart.lines());
PaymentResult paid = payment.pay(cart.total(), cart.id());
Invoice invoice = invoices.issue(cart, paid);
mailer.sendReceipt(cart.email(), invoice);
return new Receipt(invoice.id(), paid);
}
}Two other wrappers steal the same word
Interviewers will say “you wrapped it.” Name the intent. Four short lines on the whiteboard are enough.
Whiteboard test — fill left or right, never “wrapper”
Draw two columns. Left column: “Does the inner type fail to compile as my interface?” If yes, use Adapter. Right column: “Does the caller name four types to finish one use case?” If yes, use Facade. If both are true in checkout, draw both boxes and a line from Facade.Payable to the adapter. If neither is true, you are in Decorator or Proxy territory — same interface, with either extra behavior or control of access/lifetime/location.
Compile test
Could StripeClient implement Payable without mapping? No → Adapter.
Collaborator-count test
Does the controller list four collaborators? Yes → Facade.
Same-type test
Still Notifier / Image? Then Decorator or Proxy, not this page.
Adapter for a crowd of classes
If the caller must talk to five services, a translator for one of them does not help. Give them a facade. Adapt a vendor only where the type itself is foreign.
Facade for a mismatched SDK
A “StripeFacade” that only renames charge to pay is an adapter with a louder name. Facade is for a subsystem. One SDK with the wrong signature is Adapter.
Pick in ten seconds
Legacy printer with output(byte[])
Kiosk must allocate room, open folio, prep housekeeping
Need retries around Payable after Stripe is adapted
Gallery must not load DiskImage until display
placeOrder uses Payable which is StripePayableAdapter
How to explain this in an interview
“Adapter changes a foreign interface to match ours. Facade keeps interfaces and hides many classes behind one method. Decorator adds behavior on the same type. Proxy controls access, lifetime, or location. If I mix those four words, I fail the structural round.”
- Someone draws one box labeled Wrapper around Stripe and Inventory. Split it. What is each box?
- Write the one-sentence test you will use when the interviewer says “just wrap it.”
Takeaway
Adapter changes shape. Facade changes collaborator count. They may sit in the same checkout, but they answer different questions. Name the question first, then the pattern.