DEV Community

Abhirup Datta
Abhirup Datta

Posted on

Adapter Design Pattern

This is part of the design pattern series in Typescript

What and why adapter pattern is needed ?
The adapter pattern converts the interface of a class into another interface the client expects.Adapter lets classes work together that couldn't otherwise because of incomparable interfaces.

Ok, that's a lot of jargon so lets break it down πŸ”¨.

Example
Generally, we have two types of mobile charging ports - USB C and MicroUSB (or USB B).Their interfaces (port structure) are different.

Now, suppose you have a phone with MicroUSB port but you dont't have its cable, but you have a USB C cable. So what you do ?
You will get an adapter which lets you "convert" USBC to MicroUSB.

Code Snippet 1

   function charge( usbc: USBCCharger){
     usbc.chargeByUSBC();
   }
Enter fullscreen mode Exit fullscreen mode

Here are four conceptual terms that we will need to know:

  • Adapter: The connector which helps to adapt (or connect).
  • Target: A class which will be converted from. In the code snippet 1, USBCCharger is the target.
  • Client: Someone (the user) using the Target class . In the code snippet 1, function charge is the client.
  • Adaptee: The class whose methods will actually be called by the adapter.

Code snippet 2
Let us define a USBC class which has a charge method.

class USBCCharger{
    chargeByUSBC(){
        console.log("charging by USBCCharger")
    }
}
Enter fullscreen mode Exit fullscreen mode

Code snippet 3
Let us define a MicroUSB class which also has a charge method.

class MicroUSBCharger{
    chargeByMicroUsb(){
        console.log("charging by MicroUSBCharger")
    }
}
Enter fullscreen mode Exit fullscreen mode

Code snippet 4
Now, the adapter class which targets USBC charger so we can invoke charge (of Code snippet 1) by using MicroUSBCharger as an adaptee
can be written as:

class USBCAdapter implements USBCCharger{

    private usb:MicroUSBCharger;
    constructor(usb: MicroUSBCharger){
       this.usb = usb;
    }

    chargeByUSBC() {
        // can do conversions if needed etc.
        this.usb.chargeByMicroUsb();
    }
}
Enter fullscreen mode Exit fullscreen mode

Code snippet 5
Here is the test code to test the Adapter pattern
Test

function charge( usbc: USBCCharger){
   usbc.chargeByUSBC();
}

const usbC  = new USBCCharger();
charge(usbC);

const microUsb = new MicroUSBCharger();
const adapter = new USBCAdapter(microUsb);
charge(adapter);
Enter fullscreen mode Exit fullscreen mode

Output
Test code

Code for this and other patterns can be found here: https://github.com/abhidatta0/Essential-design-patterns-in-Typescript

Lets break down the USBCAdapter class (Code Snippet 4).

  1. class USBCAdapter implements USBCCharger -> The class USBCAdapter implements USBCAdapter because this is what the client charge of code snippet 1 expects

  2. constructor(usb: MicroUSBCharger) -> Here while creating an instance of USBCAdapter we need to get the reference of the object we are adapting (in this example MicroUSBCharger)

  3. chargeByUSBC method -> Now we need to implement all the methods of the target class (USBCCharger) and translate them to adaptee class(MicroUSBCharger)

Note
Don't think of the Adapter class simply as a wrapper over Adaptee class.It is for the purpose of converting the interface of a class into another interface the client expects.

The adapter pattern is a widely used design pattern in software engineering.It is often used when working with a legacy class and adapt it to a new class.

That’s it πŸ˜…

Code for this and other patterns can be found here: https://github.com/abhidatta0/Essential-design-patterns-in-Typescript

Top comments (0)