Wrap an incompatible interface so it matches the shape your code already expects.
Your code calls `logger.log(message)` everywhere. A new metrics library you want to plug in as a logger only exposes `.record(eventName, payload)`. Rewriting either side isn't realistic — one is your whole codebase, the other is a third-party package.
The adapter implements the interface your code expects, and internally calls the library's real methods, translating arguments and return values as needed. Neither side is aware the other exists.
Every other part of the app keeps calling `logger.log(...)` — only the adapter knows the underlying library exists.
// Third-party library — its shape can't be changed.
const MetricsLib = {
record(eventName, payload) {
console.log(`[metrics] ${eventName}:`, payload);
},
};
// The interface the rest of the app already expects.
class LoggerAdapter {
constructor(metricsClient) { this.metricsClient = metricsClient; }
log(message, level = "info") {
this.metricsClient.record("log_event", { level, message });
}
}
function runApp(logger) {
logger.log("Server started");
logger.log("Disk usage high", "warn");
}
runApp(new LoggerAdapter(MetricsLib));