Adapter Pattern

Pattern

Adapter is a structural design pattern that allows objects with incompatible interfaces to collaborate.

Let's explain this pattern using an example form EN.601.226 Data Structures: one of the homeworks is about implementing a (supremely) simple search engine (using hash tables) called JHUgle (cheeky! I know!!). The JHUgle uses a Map interface which is (slightly) different from Java's java.util.Map:

Namely, there are two methods insert and put where insert adds a new <key,value> pair (it would throw exception if map already contains the key). The put method on the other hand is used to update the value associated with a key (already inserted in the map). Java's Map has only a put method that convolves the behavior of our Map's insert and put.

To use Java's Map in JHUgle app, you can create an adapter for it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class JDKMapAdapter<K, V> implements Map<K, V> {
  private java.util.Map<K, V> map = new java.util.HashMap<>();

  @Override
  public void insert(K k, V v) throws IllegalArgumentException {
    if (k == null || map.containsKey(k)) {
      throw new IllegalArgumentException();
    }
    map.put(k, v);
  }

  @Override
  public void put(K k, V v) throws IllegalArgumentException {
    if (k == null || !map.containsKey(k)) {
      throw new IllegalArgumentException();
    }
    map.put(k, v);
  }

  // Implementation of other methods are omitted to save space.
}

As an aside, also note this pattern follows the Dependency Inversion Principle.

The general idea of an adapter class is similar to adapter in the physical world: think of a mobile charger as an adapter; the mobile battery needs 3 volts to charge but the normal socket produces either 120V (US) or 220V (Europe). So the mobile charger works as an adapter between the mobile charging socket and the wall socket.

When to use this pattern?

Use the Adapter when you want to use some existing class, but its interface isn't compatible with the rest of your code.

Advantage

You don't need to change the existing class or the interface. By introducing a new class, which acts as an adapter between the interface and the existing class, you reuse your existing code without changing it.