Adapter Pattern

Adapter pattern is a structural pattern. Here is the definition:

Convert the interface of a class into another interface clients expect.
Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

In other words, clients expect A, but all we’ve got is B, and yet we want to reuse B, so we introduce an adapter for B, allowing clients to use B in the way they use A without making changes to their code. Note that the adapter does not change the underline behavior implemented by B.

UML diagram and implementation

This is one way of implementing adapter pattern using composition. It is called Object Adapter.

Object adapter

Note that Adaptee can be a class or interface.

1
2
3
public interface Target {
void operateA();
}
1
2
3
4
5
public class Adaptee {
public void operateB() {
//...
}
}
1
2
3
4
5
6
7
8
9
10
11
public class Adapter implements Target {
private Adaptee adaptee;

Adapter(Adaptee obj) {
this.adaptee = obj;
}

public void operateA() {
adaptee.operateB();
}
}
1
2
Target obj = new Adapter(new Adaptee());
obj.operateA();

And there is another way called Class Adapter. It uses inheritance instead of composition.

Class adapter

Since Java (before JDK 8), I’m not quite sure how this is implemented in Java yet.

Object adapter vs. Class adapter

Another argument about “composition over inheritance”. Check this if you’re insterested.

Real Examples

In the examples below, what the adapter does is to convert the input from one format to another so that the client can deal with the output format rather than the input format.

i. Java API: java.io.InputStreamReader

As we know, BufferedReader expects a character stream, and InputeStream provides byte stream only, how can we make BufferedReader read data from InputStream without changing their implementation? The answer is to introduce an adapter as a wrapper for InputStream. As shown below, InputStreamReader serves as an adapter which converts byte stream into character stream, so the data from InputStream can be handled by BufferedReader.

1
2
3
4
URLConnection conn = new URL("http://google.com").openConnection();
InputStream is = conn.getInputStream();
BufferedReader bfReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
bfRead.readLine();

ii. JAXB: javax.xml.bind.annotation.adapters.XmlAdapter

XmlAdapter ensures that every type can be handled by JAXB, that is, if JAXB cannot map an object to an XML representation, the object will be converted from one type to another which JAXB can map to an XML representation. This is done by creating an adapter class which extends XmlAdapter and having the method marshal() and unmarshal() implemented, and this adapter class will be called when the mapping is needed. More details can be found in this post about how to use XmlAdapter.

References

1 Wikiepedia: Adapter Pattern