Adapter Pattern

The Adapter Pattern in TypeScript

2

What is the Adapter Pattern?

The Adapter Pattern is a structural design pattern that allows objects with incompatible interfaces to work together. It acts as a bridge between two interfaces, enabling integration without modifying existing code.

In simple terms: it adapts one interface to another.

Real-World Analogy

Imagine you have a U.S. laptop charger and you travel to Europe. The charger plug won't fit into the European socket. You need a plug adapter to convert the U.S. plug into a European-compatible one. The charger stays the same, but the adapter allows it to work in a new context.


When to Use the Adapter Pattern

  • You want to use an existing class but its interface doesn't match your needs.

  • You want to create a reusable class that cooperates with classes of incompatible interfaces.

  • You need to integrate third-party APIs or legacy systems with your application.


Implementing the Adapter Pattern in TypeScript

Let’s go through a practical example.

Scenario

Suppose you’re developing a payment system. You already have a PaymentProcessor interface that your application uses. Now, you want to integrate a third-party payment gateway with a different method signature.


Step 1: Define the Target Interface

ts
CopyEdit// The interface your application expects
interface PaymentProcessor {
pay(amount: number): void;
}

Step 2: Create an Adaptee (incompatible class)

ts
CopyEdit// A third-party library with a different method
class ThirdPartyPaymentGateway {
makePayment(amountInCents: number): void {
console.log(`Payment of $${amountInCents / 100} processed via third-party gateway.`);
}
}

Step 3: Implement the Adapter

ts
CopyEdit// Adapter makes the third-party class compatible with PaymentProcessor
class PaymentAdapter implements PaymentProcessor {
private gateway: ThirdPartyPaymentGateway;

constructor(gateway: ThirdPartyPaymentGateway) {
this.gateway = gateway;
}

pay(amount: number): void {
const amountInCents = amount * 100;
this.gateway.makePayment(amountInCents);
}
}

Step 4: Use the Adapter in Client Code

ts
CopyEditconst thirdPartyGateway = new ThirdPartyPaymentGateway();
const adapter: PaymentProcessor = new PaymentAdapter(thirdPartyGateway);

// Application uses a standard interface
adapter.pay(25); // Output: Payment of $25 processed via third-party gateway.

Advantages of the Adapter Pattern

  • Decouples code from third-party implementations.

  • Promotes code reuse by adapting existing components.

  • Improves maintainability when dealing with legacy systems or libraries.


Class Adapter vs Object Adapter

In languages like TypeScript, which do not support multiple inheritance, the object adapter approach (shown above) is preferred. However, in classical OOP languages like C++, you may also see class adapters, which rely on inheritance.


Conclusion

The Adapter Pattern is a powerful tool in your design pattern arsenal, especially when dealing with incompatible interfaces. In TypeScript, it helps integrate third-party APIs and legacy systems seamlessly, keeping your code clean and extensible.

By learning and applying the Adapter Pattern, you can make your applications more robust and flexible—ready to adapt to ever-changing requirements.