6

Adapter Design Pattern in TypeScript

 1 year ago
source link: https://blog.bitsrc.io/adapter-design-pattern-in-typescript-956cd3e05cec
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Adapter Design Pattern in TypeScript

How to use the Adapter design pattern in TypeScript to make your existing interface compatible with another one without changing its source code

Imagine you’re traveling to a foreign country for a business meeting. Upon settling into your hotel room, you decide to charge your laptop only to realize that the plug of your charger doesn’t match the local wall outlets. Suddenly, you’re in a pickle. But then you remember the travel adapter you brought along. You plug your charger into the travel adapter, which in turn fits perfectly into the foreign outlet. Disaster averted!

Much like this real-world situation, you may encounter similar incompatibilities in the world of software. For instance, your company has been using Slack for communication and now wants to integrate Microsoft Teams as well. However, the APIs of these two platforms don’t quite match up. How can you manage this without a major rewrite of your existing Slack integration? This is where the Adapter Pattern steps in, acting as your software “travel adapter”.

Setting the Stage for the Adapter Pattern

The Adapter Pattern allows you to make your existing interface compatible with another one without changing its source code. In software terms, it’s like having a universal travel adapter that allows your device to plug into outlets in different countries.

Adapter Pattern: Why and When?

The Adapter Pattern serves several purposes:

  1. Reusability and Compatibility: It helps you reuse existing interfaces that would have been otherwise incompatible with the system.
  2. Flexibility: It allows you to adapt to interfaces without changing the existing code.
  3. Simplicity: It simplifies the interface into high-level operations, hiding the complex underlying implementation.

You should consider the Adapter Pattern when:

  • You need to use several existing subclasses, but it’s impractical to adapt their interface by subclassing each one.
  • You want to create a reusable class that cooperates with unrelated or unforeseen classes.

💡 Implementing the Adapter pattern in your code becomes easy if you’re using tools like Bit to develop your applications. With Bit, you can easily extract any class from your codebase into its own component and then independently test, document, version and reuse it across your project.

Learn more:

Bridging Communication Tools with the Adapter Pattern in TypeScript

Let’s walk through an example of integrating our custom tool with Slack and Microsoft Teams:

1*WZLR86bxera3OPDEwVA3pg@2x.jpeg

Step 1: Define the Interface our System Expects

interface IMessageClient {
sendMessage(channel: string, user: string, message: string): void;
}

Step 2: Implement Slack Client (Adaptee)

class SlackClient {
postMessageToUserInChannel(channel: string, user: string, message: string) {
console.log(`Posting message to ${user} in ${channel} through Slack: ${message}`);
}
}

Step 3: Implement Slack Adapter

class SlackAdapter implements IMessageClient {
constructor(private slackClient: SlackClient) {}

sendMessage(channel: string, user: string, message: string): void {
this.slackClient.postMessageToUserInChannel(channel, user, message);
}
}

Step 4: Implement MS Teams Client (Adaptee)

class MSTeamsClient {
postToChannel(channel: string, message: string) {
console.log(`Posting message to ${channel} through MS Teams: ${message}`);
}
}

Step 5: Implement MS Teams Adapter

class MSTeamsAdapter implements IMessageClient {
constructor(private msTeamsClient: MSTeamsClient) {}

sendMessage(channel: string, user: string, message: string): void {
this.msTeamsClient.postToChannel(channel, `${message} (sent to ${user})`);
}
}

Step 6: Use the Adapters in Our System

const slackClient = new SlackClient();
const slackAdapter = new SlackAdapter(slackClient);

const msTeamsClient = new MSTeamsClient();
const msTeamsAdapter = new MSTeamsAdapter(msTeamsClient);

slackAdapter.sendMessage('general', 'alice', 'Hello, Alice!');
msTeamsAdapter.sendMessage('general', 'bob', 'Hello, Bob!');

In this example, both the Slack and MS Teams clients have different interfaces (postMessageToUserInChannel for Slack, postToChannel for MS Teams) than what our system expects (sendMessage). So we create adapters (SlackAdapter and MSTeamsAdapter) that implement IMessageClient and delegate calls to the respective client’s method. This way, our system can work with both Slack and MS Teams in a seamless way.

The complete code can be found in this gist.

Wrapping Up

The Adapter Pattern can play a crucial role in situations where you need to integrate a component into an existing system, but that component’s interface doesn’t match what the system expects. By providing a compatible interface, the Adapter Pattern ensures that components can work together seamlessly.

In our case, the Adapter Pattern helped us bridge the gap between two different messaging platforms — Slack and MS Teams. By writing an adapter for MS Teams, we were able to use both platforms interchangeably in our system, thus improving the versatility of our communication tools.

As with all design patterns, remember that the Adapter Pattern is just a tool in your toolbox. It’s not always the best solution and should be used judiciously. However, when the situation calls for it, the Adapter Pattern can be a real lifesaver. Use it wisely, and happy coding!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK