Mark As Completed Discussion

Adapter

If two classes cannot work together because their interfaces are different, applying the Adapter pattern helps establish compatibility between them.

For example, if one class has a function that returns XML and another class has a function that takes JSON as input, and you want to take advantage of functionality in both of these classes, you may want to implement the Adapter pattern to enable interaction between them.

It's very similar to how adapters work with consumer electronics:

  • To read a memory card from your laptop, you use an adapter.
  • To plug your European laptop into a socket in the US, you use an adapter.

Speaking of US sockets, here's an example where we use the USSocketAdapter class to make the USSocket class compatible with the ISocket interface:

1class ISocket {
2    Charge() {}
3}
4
5class GermanSocket extends ISocket {
6    Charge() {}
7}
8
9class BritishSocket extends ISocket {
10    Charge() {}
11}
12
13class Laptop {
14    Charge(socket) {}
15}
16
17class USSocket {
18    Magic() {}
19}
20
21class USSocketAdapter extends ISocket {
22    constructor(socket) {
23        super();
24        this.AmericanSocket = socket;
25    }
26
27    Charge() {
28        this.AmericanSocket.Magic();
29    }
30}

At call site, we can now wrap a US socket into the socket adapter and charge our laptop:

1// In JavaScript
2const americanSocket = new USSocket();
3const americanSocketAdapter = new USSocketAdapter(americanSocket);
4
5const laptop = new Laptop();
6laptop.charge(americanSocketAdapter);

A related pattern is Facade that provides a simplified interface to a complex subsystem. However, while Facade creates a new, simpler interface, Adapter serves to design to an existing interface.