Skip to main content

Introduction To The Adapter Pattern

The Adapter Design Pattern is a software design pattern that allows the interface of an existing class to be used from another interface. It's often used to make existing classes work with others without modifying their source code. The Adapter Pattern is especially useful when the classes that need to communicate with each other do not have compatible interfaces.

The Adapter Design Pattern can be implemented in two ways:

  1. Object Adapter Pattern: This pattern uses composition to adapt the interface of a specific object.
  2. Class Adapter Pattern: This pattern uses inheritance to adapt a class to another interface.

Classic Implementation

Let's focus on the Object Adapter Pattern as it's the more commonly used approach and TypeScript doesn't fully support classical inheritance as you would expect in other object-oriented languages.

Here's a simple example of an adapter in TypeScript:

Suppose we have a Rectangle class:

class Rectangle {
constructor(private width: number, private height: number) {}

getWidth() {
return this.width;
}

getHeight() {
return this.height;
}

area() {
return this.width * this.height;
}
}

And we have another Square class:

class Square {
constructor(private side: number) {}

getSide() {
return this.side;
}

area() {
return this.side * this.side;
}
}

As you can see, Square and Rectangle have different interfaces, so we can't use them interchangeably directly.

Suppose we need to use Square objects in a place where Rectangle is expected. We could create an adapter to make the Square class work with the code expecting a Rectangle:

class SquareToRectangleAdapter {
constructor(private square: Square) {}

getWidth() {
return this.square.getSide();
}

getHeight() {
return this.square.getSide();
}

area() {
return this.square.area();
}
}

We can now use an instance of Square where a Rectangle is expected:

let square = new Square(5);
let adapter = new SquareToRectangleAdapter(square);

console.log(adapter.getWidth()); // 5
console.log(adapter.getHeight()); // 5
console.log(adapter.area()); // 25

This way, the SquareToRectangleAdapter class adapts the interface of the Square class to the Rectangle interface, allowing Square objects to be used where Rectangle objects are expected.

When To Use Adapter Pattern

  1. Incompatibility of interfaces: This is the most common scenario where the Adapter pattern is useful. When two parts of a system have different interfaces and need to communicate with each other, the Adapter pattern can help to "translate" between the two interfaces. This situation can arise often when integrating third-party libraries or APIs that don't directly fit into your application's design.

  2. Refactoring of legacy code: In case of a system redesign where you want to maintain backward compatibility, the Adapter pattern can serve as a bridge between the new systems and the old ones. Instead of rewriting old interfaces, you can use an Adapter to match the new interfaces.

  3. Alternatives to multiple inheritance: In languages that don't support multiple inheritance (like TypeScript or Java), the Adapter pattern can help to achieve similar goals. When a class needs to inherit behavior from multiple sources, adapters can provide an alternative way to reuse functionality.

  4. Abstracting volatile classes: Sometimes you might need to abstract the use of volatile classes (ones that change often). The Adapter can encapsulate these changes so that the impact on the rest of the application is minimized.

TypeScript Course Instructor Image
TypeScript Course Instructor Image

Time To Transition From JavaScript To TypeScript

Level Up Your TypeScript And Object Oriented Programming Skills. The only complete TypeScript course on the marketplace you building TypeScript apps like a PRO.

SEE COURSE DETAILS

What Can You Do Next 🙏😊

If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for ssoftware developers.

YouTube @cloudaffle