← back to the blog


JavaScript Adapter Pattern

Posted on September 20th, 2020 in JavaScript by George

 

In this tutorial we have an example of how to use the "Adapter Pattern" design pattern with JavaScript.

We have two APIs that do the same thing, reversing a string and returning a custom output, as upper case. ReverseV1 and ReverseV2.

You could think of ReverseV1 as the legacy API which has to be replaced gradually.

The ReverseV2 API is more modular and gives to the developer more flexibility.

The problem the "Adapter Pattern" solves, is the ability to provide the new API to applications that rely on the old API interface, without breaking the functionality and most important without the need to modify the application eveywhere where our method has been used.

If this does not make sense, it may be useful to have a look over some examples.

The code written below is functional but as I am sure you already assumed, is only a proof of concept, a simplified version of what a real life system could be.

 

1.The old API

The main method, "reverseAndUpperCase" has been use in our applications in many places.

Our next task is to replace the old deprecated api and to replace it with the new one.

 

class ReverseV1 {
  constructor(word) {
    this.word = word;
  }

  reverseAndUpperCase(){
    let translated = `Result: ${[...this.word].reverse().join("").toUpperCase()}`;
    return translated;
  }
}

let reverseFirst = new ReverseV1('house');

console.log('Test 1:', reverseFirst.reverseAndUpperCase());
//Output Test 1: Result: ESUOH

 

2. The new API

ReverseV2 can do the same thing as the old API but has more methods available, which gives more flexibility and more functionality to the developers.

 

class ReverseV2 {
  constructor(word){
    this.wordToTranslate = word;
  }

  reverseWord() {
    return [...this.wordToTranslate].reverse().join("");
  } 

  uppercaseWord() {
    return this.reverseWord(this.word).toUpperCase();
  }

  outputUpper() {
    return `Result: ${this.uppercaseWord(this.word)}`;
  }

  outputDefault() {
    return `Result: ${this.word}`;
  }

}

let reverseSecond = new ReverseV2('consciousness');

console.log('Test 2: ', reverseSecond.outputUpper());
//Output Test 2: Result: SSENSUOICSNOC

 

3. The Adapter

In order to be able to replace our old API with the latest version we could take advantage of the "Adapter Pattern".

Adapter pattern is a structural pattern where the interface of one class is translated into another. This pattern allows classes work together that could not otherwise, because of incompatible interfaces.

 

class ReverseAdapter {
  constructor(word) {
    this.newApi = new ReverseV2(word);
    this.reverseAndUpperCase = function() {
      return this.newApi.outputUpper();
    }
  }
}

let reverseAdapted = new ReverseAdapter('house with new api');

console.log('Test 3: ', reverseAdapted.reverseAndUpperCase());
//Output: Test 3: Result: IPA WEN HTIW ESUOH

 

As you can see, using the Adapter will allow the method "reverseAndUpperCase" to use the new API.

As I have mentioned at the beggining of the article, this is not an example of the best practices but rather a proof of concept over the "Adapter Pattern".

Thank you.