🙋🏻♀️ What is the Adapter Pattern?
The Adapter Pattern is a design approach that allows objects with incompatible interfaces to work together.
When objects cannot directly communicate, the Adapter
class, as an intermediary, effectively adapts the interface of one object to match the interface expected by the other object.
✨ Simple TypeScript Example
You can implement the Adapter Pattern by using either class inheritance or object composition.
In the class inheritance approach, the Adapter
class extends the incompatible class and implements the desired interface.
Let’s say you have a Client
interface representing the desired interface that the client code expects. Service
class represents an existing class or object with an incompatible interface.
interface Client {
request(): void;
}
class Service {
performOperation(): void {
console.log("Performing operation");
}
}
The Adapter
class implements the Client
interface and acts as an intermediary between the client code and the Service
class.
// Adapter class using Class Inheritance
class Adapter extends Service implements Client {
request(): void {
this.performOperation();
}
}
// Client code
const client: Client = new Adapter();
client.request();
On the other hand, in the object composition approach, the Adapter
class contains an instance of the Service
class and delegates the requests to it, while still implementing the desired interface.
// Adapter class using Object Composition
class Service implements Client {
private service: Service;
constructor(service: Service) {
this.service = service;
}
request(): void {
this.service.performOperation();
}
}
// Client Code
const service: Service = new Service();
const client: Client = new Adapter(service);
client.request();
🧑🏻💻 Use it or Avoid it
When to use it
The Adapter Pattern is especially useful when integrating legacy code or reusing existing classes because the Adapter Pattern can bridge the gap and allow them to work together without modifying the existing code.
This pattern can also be an appropriate solution for promoting decoupling. An adapter
will help you to separate the client code from the implementation details of an external API, making it easier to switch or update the underlying implementation later.
When to avoid it
It’s important to consider the trade-offs and whether the additional abstraction is truly necessary. The Adapter Pattern might not be suitable if you can directly perform the required transformations in the client code, or oppositely using Adapter
is not sufficient because the incompatible objects have different internal logic fundamentally.