Adapter (Structural)
Intent / problem it solves
Convert one interface into another so existing classes work with callers that expect a different API—without changing the original implementation.
When to use / when NOT
Use when integrating third-party SDKs, legacy modules, or streaming APIs into your domain types.
Avoid when you control both sides; refactor to a shared interface instead of piling adapters forever.
Structure
Adapter implements the target interface and delegates to adaptee (object adapter) or subclasses it (class adapter, in languages that allow).
Go example
package main
import (
"fmt"
"time"
)
type LegacyLogger struct{}
func (LegacyLogger) WriteLine(prefix, message string) {
fmt.Println(prefix, message)
}
type AppLogger interface {
Info(message string)
}
type LegacyLoggerAdapter struct {
legacy LegacyLogger
}
func (adapter LegacyLoggerAdapter) Info(message string) {
adapter.legacy.WriteLine(time.Now().Format(time.RFC3339), message)
}
func main() {
var logger AppLogger = LegacyLoggerAdapter{legacy: LegacyLogger{}}
logger.Info("service started")
}JavaScript example
class PaymentSdk {
chargeCents(amountCents, metadata) {
return { ok: true, amountCents, metadata };
}
}
class CheckoutPort {
chargeDollars(amountDollars, context) {
throw new Error('override');
}
}
class PaymentSdkAdapter extends CheckoutPort {
constructor(sdk) {
super();
this.sdk = sdk;
}
chargeDollars(amountDollars, context) {
const cents = Math.round(amountDollars * 100);
return this.sdk.chargeCents(cents, context);
}
}
const adapter = new PaymentSdkAdapter(new PaymentSdk());
console.log(adapter.chargeDollars(12.34, { orderId: '42' }));Interview phrase
“Adapter is my integration boundary: the domain talks to CheckoutPort, and I translate to whatever stripe-like SDK shape exists today.”
Related LLD case studies
Place adapter sketches next to ports in LLD case studies when external APIs differ from internal interfaces.
Last updated on
Spotted something unclear or wrong on this page?