Sunday, June 26, 2022

How to use Adapter Design Pattern in Java with Example

The adapter design pattern in Java, also known as the Wrapper pattern is another very useful GOF pattern, which helps to bridge the gap between two classes in Java. As per the list of Gang of Four patterns, the Adapter is a structural pattern, much like Proxy, Flyweight, Facade, and Decorator patterns in Java. As the name suggests, the Adapter allows two classes of a different interface to work together, without changing any code on either side. You can view the Adapter pattern as a central piece of the puzzle, which joins two pieces, which can not be directly joined because of different interfaces.

I see a couple of references for the Adapter design pattern in one of my favorite books Clean Code, but the idea is very well explained in Head First Design Pattern, the image which they show to illustrate the Adapter design pattern is worth all the talk.

By the way, Adapters are everywhere in real life, most commonly when we talk about Adapter, we mean electrical adapters. If you have got an onsite opportunity and had visited the US, UK, or any other European or North American country, you might have seen different kinds of electrical sockets than in India as the USA has a rectangular socket, as compared to a cylindrical one from India.

Basically, when we talk Electrical adapter, we talked about an adapter that changes the voltage or the ones which allow using a plug designed for one country in a Socket of another country.

This example shows an important attribute of an Adapter design pattern in software development, you can neither change the Socket of the visiting country, neither can you change the plug of your laptop, So you introduce an Adapter, which makes things working without changing any party. Similarly, the Adapter design pattern makes incompatible interfaces work together, without changing them. Only a new code that is inserted is in the form of an Adapter or Wrapper class.

Btw, If you are serious about learning design patterns and principles, I suggest you take a look at these Design Patterns in Java courses on Udemy.  This course covers both SOLID design principles like Open Closed and Liskov substitution, and all-important Object Oriented design patterns like Decorator, Observer, Chain of Responsibility, and much more.





How to implement the Adapter Design pattern in Java?

There are two ways to implement the Adapter design pattern in Java, one using Inheritance also known as the Class Adapter pattern and the other is using Composition, better known as Object Adapter pattern. In both cases, it's better to declare client interacting public methods in an interface, you may call it target interface.

One advantage of using a target interface to wrap the client-facing method in an Adapter, you create a loosely coupled design, where you can replace your Adapter with better implementation in the later stage of development.

Now your Class Adapter pattern extends the original interface, which is incompatible to the client but provides the functionality needed by the client, and it also implements the target interface. Now, the Adapter implements the target method in such a way that it delegates actual work on the original class, to which Adapter gets access by extending it.

Similarly, in the case of the Object Adapter pattern, which uses Composition for reusing code, it also implements the target interface and uses the object of the Original incompatible class to do all of its work. It's better to prefer composition over inheritance, I advise that you should stick with the Object Adapter pattern.

here is a UML diagram of the Adapter design pattern which will make things easier to understand and also clear any doubt you have about the structure of this pattern:

UML diagram of Adapter design pattern in Java


In this example, the Client is a target interface and the Wizard is the Adaptee. In order to facilitate the use of Wizard, we have created WizardAdapter which implements target interface Fighter but delegates work to Adaptee.



Adapter pattern in Java - Map Adapter

Let's see one more example of the Adapter pattern in Java. If you remember the java.util.Map has no way to automatically load a two-dimensional array of objects into a Map as key-value pairs. We can create an adapter class that does this.

Sometimes the problem you are solving is as simple as "I don't have the interface I want". Two of the patterns in the list of GOF design patterns, Adapter, and Facade pattern solve this problem by providing an alternate interface.

The adapter pattern takes whatever interface you have and produce the interface you need. While Facade pattern provides a simpler interface to deal with a number of classes or bundle of resources.

Here is my implementation of Adapter pattern in Java to convert a two-dimensional array of objects into Map of key-value pairs


Java Program to implement Adapter design Pattern

import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Implementation of Adapter pattern in Java. The java.util.Map has no way to
 * automatically load a two dimensional array of objects into a Map as key-value
 * pairs. This Java program creates an adapter class that does this.
 * 
 * @author WINDOWS 8
 */

public class Test {

    public static void main(String args[]) {
        
        Integer[][] squares = { {2, 4}, {3, 9}, {4, 16}};

        MapAdapter adapter = new MapAdapter(squares);
        
        System.out.println("adapter map contains : " + adapter);
    }

}

/*
 * This class is an adapter which allows to create a Map by providing a two
 * dimensional array of keys and values. It extends AbstractMap class so that it
 * become a Map and can be passed around where a Map is needed. All other method
 * is implemented in AbstractMap except the adapter functionality which is
 * implemented in constructor of this class.
 */
class MapAdapter extends AbstractMap {
    private Map map;

    public MapAdapter(Object[][] array) {
        super();
        map = new HashMap();
        for(Object[] mapping : array){
            map.put(mapping[0], mapping[1]);
        }

    }

    @Override
    public Set entrySet() {
        return map.entrySet();
    }

}


Output
adapter map contains : {2=4, 3=9, 4=16}

You can see that our MapAdapter extends AbstractMap to create a Map that can take a two-dimensional array and create a HashMap from that.

Here is one more interesting diagram which will help you to understand the intent and purpose of the Adapter pattern in Java. You can see that your existing system and vendor class don't fit initially but when you add an Adapter the puzzle is solved and both systems are able to plug together.


Adapter pattern example in Java





Important points about Adapter Pattern in Java

Now, let's see some important points about Adapter Patterns in Java. These points will to only provide you why and when to use the Adapter design pattern but also other benefits and drawbacks for Adapter pattern in software development in Java. 

1. Adapter design pattern ensures code reusability for delegating calls from the client to the original class, i.e. it acts like a wrapper of the original interface, that's why it's also called a wrapper pattern or simply a wrapper. This is actually the main benefit of using the Adapter pattern.


2. Adapter pattern is a general-purpose pattern, much like Singleton, Factory, and Decorator and you will see a lot of examples of Adapter patterns through the code, one of the key benefits of using Adapter patterns in Java is reusing code, making incompatible interfaces work together and loose coupling because Adapter tends to encapsulate incompatible interface quite well.


3. One of the cases where you want to use the Adapter design pattern in Java program is while using a third-party library. By making sure, your program uses an Adapter, which is in your control, rather than directly using third-party interfaces and classes, you can anytime replace third-party library, with similar, better-performing API. You can count this one of the pros of using Adapter pattern.

4. In the Gang of Four design patterns, Adapter pattern is part of structural design pattern along with Proxy, Facade, and Decorator design pattern.

5. A lot of programmers confuse between the Adapter and Decorator design pattern in Java, to some extent they are similar, especially object based adapter pattern but there is a subtle difference between the Decorator and Adapter pattern in Java. Adapter just converts one interface to another, without adding additional functionalities, while Decorator adds new functionality into an interface. See here to learn more about the difference between Adapter and Decorator pattern in Java.

6. You can also use Adapter design pattern in Java for conversion classes, e.g. Suppose your client do all calculation in Miles and the library you are using expects Kilometers. In this case, you can write an Adapter class, which takes miles from Client, converts it to Kilometer and leverages external library methods for all calculation. While returning a result, it can convert KM back to miles and send the result to Client.

7. Prefer Object-based Adapter design pattern than Class-based, because the former uses Composition for code re-use and more flexible than Inheritance based approach of Class based Adapter pattern in Java.


That's all on what is an Adapter design pattern in Java, How and when to use Adapter pattern and the difference between Class and Object-based implementation of the Adapter design pattern. The adapter is a really useful general-purpose pattern and Java developers should take advantage of this pattern as much as possible to write flexible code.


Other Java design pattern tutorials you may like
  • What is the difference between State and Strategy pattern in Java? (answer)
  • How to implement Strategy pattern in Java? (example)
  • 5 Best Software Architecture Books for experienced (Books)
  • How to design a Vending Machine in Java?  (solution)
  • What is the difference between Factory and AbstractFactory pattern in Java? (answer)
  • How to implement dependency injection in Java? (solution)
  • What is the difference between Factory pattern and Dependency injection? (solution)
  • How to implement Command design pattern in Java? (solution)
  • How to implement Data Access Object Pattern in Java? (solution)
  • How to create Strategy pattern using Enum in Java? (example)
  • Top 5 Books to learn System Design for Beginners (Books)

Thanks for reading this article so far. If you like this design pattern tutorial and my explanation of Adapter Patter in Java then please share with your friends and colleagues. If you have any questions, feel free to ask in comments.

P.S. - If you want to learn design pattern in depth but looking for best free design pattern courses then don't worry, I have recently shared 5 best free design pattern courses, you can check that article to find out the best free design pattern course for you. 


8 comments :

yep! said...

I think that `MapAdapter` is a poor example as there could be just a single static method that makes a conversion, and you don't even need an adapter to *convert* an array to a map. A better example might one of, say:

* converting `com.google.common.base.Function` to `java.util.function.Function` or vice versa;
* converting `com.google.common.base.Converter` to `org.springframework.core.convert.converter.Converter` or vice versa.
* converting `java.util.Enumeration` to `java.util.Iterator`
* etc...

Such adapters keep references to instances of their source types being just views and true adapters. `Arrays.asList(...)` might be a good example too as it keeps reference to the source array, and not just makes a conversion. If making a simple conversion, then just a simple `a+b` might be considered as adaption of two numbers to its sum. :)

Anonymous said...

I think the example is quite similar to Arrays.asList(), the MapAdapter class keep reference of Map and even though author has only define entrySet() method where it delegate function to kept Map reference, he could have define all other Map methods, but nonetheless they are available because MapAdapter class cleverly extends AbstractMap.

Though I agree that the examples e.g. Enumeration to Iterator or com.google.common.base.Function and java.util.function.Function better highlight the power of Adapter pattern.

SARAL SAXENA said...

well javin few things can be added to get more clear description..

Target :-
defines domains-specific interface client uses.
Client :-
collaborates with objects conforming to target interface.
Adaptee :-
defines existing interface that needs adapting
Adapter :-
adapts the interface of adaptee to target interface.

SARAL SAXENA said...

WorkFlow of adapter pattern :-

Clients call operations on the adapter instance.In turn adapter calls adaptee operations that carry out the request.

Unknown said...

Even if the adapter design pattern is known as the Wrapper design pattern as well, it is misleading because adapters and wrappers are NOT the same thing. They are often mistakenly used interchangeably. However, a wrapper is used to simplify a complex interface for a more specific instance, and an adapter allows an input from one interface to be translated to another. It "adapts" it to the other "environment". A wrapper "wraps" the interface into a simpler bundle.

javin paul said...

I agree @Unknown and you have summed it very aptly. In Adapter, input and output interface is always different.

Arun Kumar said...

We can also use Adapter pattern in following scenarios:
* When client wants to interact with existing system using incompatible interface.
* When a new system wants to interact with legacy(old) system using new interface which is not compatible with interface of legacy system.
* When you want to use a 3rd party framework or library whose interface is incompatible with your system.

javin paul said...

Hello Arun, thanks for adding value, Yes, those are valid usage, do you also have examples which you can share to make understanding even better?

Post a Comment