Structural 1 — Adapter
In one line
Make an incompatible interface look like the one your client expects — a translator between contracts.
Think of it like this
A travel plug adapter. Your Indian charger doesn't fit a UK socket, so the adapter sits in the middle and makes them work together without changing either.
Key ideas
- 01
Solves: integrating a third-party/nice-to-have API without polluting your domain code.
- 02
Class adapter (inheritance) vs object adapter (composition) — prefer composition.
- 03
In interviews: payment gateways, notification providers, SDKs, legacy systems.
Java / Spring map
- →
Spring: a @Bean returning an adapter wraps a vendor SDK into your domain interface.
Code & diagrams
A vendor SDK (Twilio) adapted to our own SmsSender contract.
// our domain contract
public interface SmsSender { void send(String to, String text); }
// third-party SDK with a DIFFERENT shape
public class TwilioClient {
public void sendMessage(String recipient, String body, boolean urgent) { /* ... */ }
}
// adapter: translates our interface to theirs
public class TwilioSmsAdapter implements SmsSender {
private final TwilioClient twilio;
public TwilioSmsAdapter(TwilioClient twilio) { this.twilio = twilio; }
public void send(String to, String text) {
twilio.sendMessage(to, text, false); // contract translation happens here
}
}Explain without notes
Where does the translation live and why is that a good thing?
Practice
Adapt a hypothetical LegacyOrderService into a modern OrderRepository interface.
Trade-offs
- ↔
An adapter hides the vendor quirks — you must still handle vendor retries/errors at the boundary.
Completion checklist
I can wrap any third-party SDK behind a domain interface and translate its errors into domain exceptions.