Skip to content

Adapter Design Pattern

Posted on:September 23, 2022 at 03:22 PM

Wikipedia defines the Adapter Pattern as:

In software engineering, the adapter pattern is a software design pattern that allows the interface of an existing class to be used as another interface. It is often used to make existing classes work with others without modifying their source code.

Let’s see this in action. Let’s suppose we are building a Duck simulator.

interface Duck {
  quack();
  fly();
}

We have a Duck interface which consists of two methods.

class MallardDuck implements Duck {
  display() {
    // displays mallard duck
  }

  fly() {
    // implement swim behaviour
  }

  quack() {
    // implements quack behaviour
  }
}

We have MallardDuck which implements the Duck interface.

class DuckSimulator {
  constructor() {
    const duck = new MallardDuck();
    this.quackAndFly(duck);
  }

  quackAndFly(duck: Duck) {
    duck.quack();
    duck.fly();
  }
}

Inside the DuckSimulator we create a new Duck instance of MallardDuck and assign it to the duck. So far everything is working fine. If we call the quackAndFly method of the DuckSimulator it will execute the fly and quack method of MallardDuck

Now let’s suppose we want to add Turkey into our DuckSimulator.

interface Turkey {
  gobble();
  fly();
}

The Turkey interface is slightly different from the Duck’s interface so we can not add it directly to our DuckSimulator.

class WildTurkey implements Turkey {
  gobble() {
    console.log("gobble!");
  }

  fly() {
    console.log("Fly");
  }
}

We can not use Turkey in DuckSimulator because DuckSimulator expects the type objects to be of type Duck and the interface for Duck and Turkey have differences due to which it can not be used.

To overcome this we can use an Adapter. An Adapter acts as a bridge between Duck and Turkey objects.

We will create a new class called TurkeyAdapter. This class will act as an adapter between Duck and Turkey.

This class will implement the Duck interface so we can directly plug it into the Duck class. Inside the implementation of Duck

class TurkeyAdapter implements Duck {
  constructor(private turkey: Turkey) {}

  quack() {
    this.turkey.gobble();
  }

  fly() {
    this.turkey.fly();
  }
}

Now we can use this inside the DuckSimulator

class DuckSimulator {
  constructor() {
    const duck = new MallardDuck();
    this.quackAndFly(duck);
    const wildTurkey = new TurkeyAdapter(new WildTurkey());
    this.quackAndFly(wildTurkey);
  }

  quackAndFly(duck: Duck) {
    duck.quack();
    duck.fly();
  }
}