The blog for Design Patterns, Linux, HA and Myself!
In this section we’ll be learning about the object oriented programming(OOP)‘s Adapter Patter or Adapter Design Pattern. We’ll work on a currency converter to understand the concept behind the Adapter Design Pattern in this tutorial. In the later part of this document, we’ll be looking into some use case scenarios suitable for the Adapter Design Pattern.
Let’s assume you’ve an existing software system that fetches the current INR(India Rupees) to USD(US Dollars) live exchange rates from current-rates.com. But one day you find that your system is not able to get the current exchange rates.
After some research you found that response that your system expects is different from the actual response. Maybe, the exchange rate service has added a new field in the message. Anyway, it’s your system that got impacted.
What can you do to solve this problem?
You can update your system’s code by changing the message format. But you’ll have to keep on doing it whenever there’s a change in the exchange rate service. Also, this is possible if and only if you can change the code of the receiver, i.e., your software system.
You can create an adapter that adapts to the exchange rate service. So, whenever there’s a change in the exchange rate service the adapter makes sure that your software system receives the response in the expected format only.
Also, whenever the exchange rate service change their response there won’t be any impact on your system as the changes will be handled(or adapted) by the Adapter.
Here’s how it’ll work:
ExchangeRateAPI
, for communicating with the exchange rate APIs.ExchangeRateAPIManager
, to you so that you can hit their APIs.ExchangeRateAPI
and it will have a has-a relationship with the
ExchangeRateAPIManager
.Let’s take a look at a scenario where Adapter Design pattern can be helpful.
Some Java classes, like, Stack
, have method elements()
that returns an Enumeration
. The Enumeration
interface
has two methods, hasMoreElements
and nextElement
. It’s there since JDK 1.0.
But Java has moved on, and it brought Iterator
in the Collection framework. But in a lot of APIs you can find
Enumerations
are still being used. What we can do here is we can create an adapter for Enumerations so that whenever the
client has an Iterable interface then it can use this Adapter so that Enumerations get adapted into Iterables.
Note: Make sure to go through the code comments as well. It’ll help you understand the concept better.
/**
* EnumerationIterator is an adapter for Enumerations. It uses Iterables internally.
*/
class EnumerationIterator<T> implements Enumeration<T> {
private Iterator<T> iterator;
public EnumerationIterator(Iterator<T> iterator) {
this.iterator = iterator;
}
@Override
public boolean hasMoreElements() {
return iterator.hasNext();
}
@Override
public T nextElement() {
return iterator.next();
}
}
This class, EnumerationIterator
, implements the Enumeration
interface, and it expects an Iterator
in the constructor.
Internally, it uses this adapter to get the data or information but the client of this interface uses it as an Enumeration
.
The vice versa as well:
/**
* IteratorEnumeration is an adapter for Iterator. It uses Iterables Enumeration.
*/
class IteratorEnumeration<T> implements Iterator<T> {
private Enumeration<T> enumeration;
public IteratorEnumeration(Enumeration<T> enumeration) {
this.enumeration = enumeration;
}
@Override
public boolean hasNext() {
return enumeration.hasMoreElements();
}
@Override
public T next() {
return enumeration.nextElement();
}
@Override
public void remove() {
throw new UnsupportedOperationException("Enumerations do not support removal of elements.");
}
}
Can a whiteboard pen be used as a simple pen to write on a paper? For that to happen, the whiteboard pen must adapt itself into a simple pen.
Finally the definition from the Wikipedia
In software engineering, the adapter pattern is a software design pattern (also known as wrapper, an alternative naming shared with the decorator pattern) that allows the interface of an existing class to be used as another interface.
InputStream
,
but you are getting an Array
. In this scenario, you can use the java.io.ByteArrayInputStream
class whose constructor
expects a byte array.public ByteArrayInputStream(byte buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}
I’ve created these tutorials after learning Design Patterns from this book Head First Design Patterns (A Brain Friendly Guide).