Skip to content

The adapter pattern

Purpose

The adapter pattern allows us to create a new interface around an existing class. This is useful when a class has the behaviours we need, but they're implemented in a way that isn't compatible with the rest of our software.

For example, we might have legacy code for older smart lights:

js
class OldLight {
  constructor() {
    this.power = 1
  }

  on() {
    this.power = 1
  }

  off() {
    this.power = 0
  }
}

Using the adapter pattern, we can wrap this old code in an adapter so that we expose an isOn property and a togglePower() method, bringing it in line with the newer SmartLight class.

Implementation

We create an adapter class which accepts an instance of OldLight, and interacts with this instance to replicate the newer SmartLight interface.

js
class LightAdapter {
  #oldLight
  constructor(oldLight) {
    oldLight.off() // make sure it's off by default
    this.#oldLight = oldLight
  }

  get isOn() {
    return this.#oldLight.power === 1
  }

  togglePower() {
    if (this.isOn) {
      this.#oldLight.off()
    } else {
      this.#oldLight.on()
    }
  }
}

Now, we can wrap an old light in the adapter so that its interface is identical to a smart light.

js
const oldLight = new OldLight()
const adaptedLight = new LightAdapter(oldLight)

console.log(adaptedLight.isOn) // false
adaptedLight.togglePower()
console.log(adaptedLight.isOn) // true