Adapter Pattern — A Quick Guide
Design Patterns: Adapter Pattern
--
“Adapter Pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.”
Simple Example:
Suppose you are traveling from Europe to USA, since there are different outlets being used, you need an adapter/wrapper/converter for you to be able to use your devices.
Real-Life Example:
Suppose you are writing an app and you are using a Kafka client to consume messages from a topic.
This client has methods called consume and produce to read and write messages to a Kafka topic and the broker you are listening the topic from has version 1.8.
Let’s call this: Client A.
Now you need to listen to an another topic from another broker.
This broker has version 2.4 and your Kafka client does not support this version yet. You find another Kafka client to help you.
Let’s call this: Client B.
But there is a problem: You wrote all your code according to Client A but
Client B uses different convention.
For example, it uses the name read instead of consume and uses the name write instead of produce.
You don’t want to migrate all your code to Client B, because you’ve heard that Client A will soon start supporting newer versions and Client B overall uses more memory than Client A.
Since our code should be open for extension, but closed for modification, the best thing to do there is to not touch existing code and just wrap Client A’s code around Client B to work with existing logic.
There may be lots of other similar scenarios to use Adapter Pattern, it’s a very common need to convert types to each other.
Implementation
public class ClientBAdapter extends ClientA {
private final ClientB clientB;
public ClientBAdapter(ClientB clientB) {
this.clientB = clientB;
}
@Override
public void consume() {
clientB.read();
}
@Override
public void produce() {
clientB.write();
}
}
With this approach, ClientB can easily act like ClientA.
ClientB clientB = new ClientB();
clientB.write();
clientB.read();
ClientA clientBAdapted = new ClientBAdapter(clientB);
// feel free to use a static helper method instead of a constructor
clientBAdapted.consume();
clientBAdapted.produce();
It works!
We didn’t change any existing code, just wrote one helper class.
Simple and a quick solution. :)
Facade and Adapter both wrap multiple classes, but a Facade’s intent is to simplify, while an Adapter’s is to convert the interface to something different.
Thank you for reading and being a part of my journey!
Reference(s)
- Head First Design Patterns. by Eric Freeman, Elisabeth Robson, Bert Bates, Kathy Sierra. Released October 2004. Publisher(s): O’Reilly Media, Inc.