Adapter Pattern: Travel around the world as Pro Tennis Player

Adapter Pattern: Travel around the world as Pro Tennis Player

Imagine you are a professional tennis player who travel around the world for important tournaments but you are not able to speak any language other than English... So, in every non-english country you need someone to helps you with the speech. You might need to hire a professional interpreter to adapt your speech into the fan's country...

Given the above context, let's have a look at the definition of the Adapter Pattern:

"Adapter pattern allows objects with incompatible interfaces to work together".

And also, here is the Adapter Pattern class diagram:

Client: The component which is implemented against the target interface.

Target: The expected interface that the client invokes method on.

Adapter: The code that allows implement the interface that the client implements which has the ability to "talk" with the "adaptee" class.

Adaptee: is the library, component or system that we are not able to change.

Hiring a professional interpreter

Backing to the Profesional Tennis Player example; We have a player who is an english speaker and fans around the world (non-english speaker). As the player's fans doesn't speak english and we can not change the way that fans speaks we will use a "profesional interpreter" to translate the player's speech into the fan's language rather than learn every single language.

Before writing the code, let's look at the class diagram:

Greetings: A polite word or sign of welcome

TennisPlayer: Is the client who uses an english interface to say hello

SpanisInterpreterAdapter: Is the interpreter who can understand english and also, speak Spanish.

Spanish: Thats represent the language of the player's fans

Target

The IGreetings interface represents the "Target" node of the Adapter Pattern diagram. We have a simple interface with one method to say hello:

export interface IGreetings {
  sayHello: () => void;
}

Adapter Class

The SpanishInterpreterAdapter class represents the "Adapter" node of the Adapter Pattern diagram. Also, this class implements the IGreetings interface because it is able to connect both incompatibles languages:

import { IGreetings } from "./greetings.interface";
import { Spanish } from "./spanish";

export class SpanishInterpreterAdapter implements IGreetings {
  constructor(private spanish: Spanish) {}
  sayHello(): void {
    // the interpreter know's how to say hello in spanish 
    this.spanish.decirHola();
  }
}

Adaptee Class

The Spanish class represents the "Adaptee" node of the Adapter Pattern diagram. We have a simple class with one method to say hello in spanish:

export class Spanish {
  //sayHello means decirHola in Spanish
  decirHola(): void {
    console.log("Hola!");
  }
}

Client

This is our Profesional Tennis Player which represents the "Client" node of the Adapter Pattern diagram:

import { Spanish } from "./src/spanish";
import { SpanishInterpreterAdapter } from "./src/spanish-interpreter.adapter";

// our professional tenis now is playing an important match in Spain
// we need to hire an interpreter to translate their speech from English to Spanish
const spanishInterpreterAdapter = new SpanishInterpreterAdapter(new Spanish());

spanishInterpreterAdapter.sayHello();
// Hola! (means hello in english)

Conclusions

Often we can get "Facade pattern" and "Adapter pattern" confused. The main difference between they is their purpose: "facade pattern" simplifies interactions with a complex subsystem, while "adapter pattern" helps to make incompatible interfaces work together.

The adapter pattern is used when you need to adapt an existing class to meet the needs of a new interface, rather than simplifying access to a complex subsystem.

I hope that this article was useful for improve your design patterns skills.

See you in the next one!

Did you find this article valuable?

Support Max Martínez Cartagena by becoming a sponsor. Any amount is appreciated!