Adapter
Make two incompatible interfaces work together by wrapping one in an Adapter that translates calls — like a power plug converter for your code.
Intent & Description
🎯 Intent
Let an existing class work in a context that expects a different interface — without modifying either class.
📋 Context
You’re integrating a third-party library, legacy system, or SDK that has a useful implementation but a completely different interface from what your codebase expects. You can’t modify the external class and don’t want to rewrite the consumers.
💡 Solution
Create an Adapter class that implements the interface your code expects and internally holds a reference to the adaptee (the incompatible class). The Adapter translates method calls: adapter.newMethod() maps to adaptee.oldMethod(). Consumers never know they’re talking to an adapter.
Real-world Use Case
Source
📌 TL;DR
Wraps an incompatible class in a translator. Client calls the interface it expects; Adapter converts to what the adaptee understands. Essential for integrating third-party code cleanly.
Advantages
- Integration code stays separate from business logic — clean Single Responsibility.
- Add new adapters without touching existing client code or the adaptee.
Disadvantages
- Adds a class and indirection layer — minor overhead for simple integrations.
// Old interface
class OldCalculator {
operations(t1, t2, operation) {
switch (operation) {
case 'add': return t1 + t2;
case 'sub': return t1 - t2;
default: return NaN;
}
}
}
// New interface
class NewCalculator {
add(t1, t2) { return t1 + t2; }
sub(t1, t2) { return t1 - t2; }
}
// Adapter
class CalcAdapter {
constructor() {
this.cal = new NewCalculator();
}
operations(t1, t2, operation) {
switch (operation) {
case 'add': return this.cal.add(t1, t2);
case 'sub': return this.cal.sub(t1, t2);
default: return NaN;
}
}
}