Other Tutorials

Adapter Design Pattern In Java

Introduction:

The Adapter design pattern is a structural design pattern that helps us to connect to the legacy or third-party code that exposes a similar functionality through a different interface.

A real-world analogy for an adapter is the one we use to connect our USB cable to an ethernet port.

While designing an object-oriented application, we might feel the need for an adapter when say our client expects an object of a specific type and we have a third-party API offering the same functionality but through an incompatible interface. 

Adapter Pattern

It’s also popularly known as a wrapper as it wraps an existing code with a new interface making it compatible for the client.

Terminologies:

Let’s be aware of the terms we use when talking about an adapter pattern:

  • Client: the class that wants to use the third-party library or the external system
  • Adaptee: a class in the third-party library or the external system that we want to use
  • Target interface: the desired interface that the client will use
  • Adapter: this class sits between the client and the adaptee and implements the target interface

Using the Adapter Pattern:

Let’s say we have a ShopInventory which maintains a list of products. Later on, we took over another store inventory which sells groceries. We now want to add those items to our ShopInventory. The problem we have here is that although the GroceryItem is just a type of product but is unrelated to the Product interface.

To solve this problem, we’ll use the adapter pattern. We’ll create a GroceryItemAdapter which will implement the Product interface:Adapter Pattern Example

With the help of an adapter, we’ll now be able to treat the GroceryItem as a Product without changing anything in the third-party code(GroceryItem).

Java Implementation:

Let’s first start by defining a Product and a ShopInventory class:

public interface Product {

    String getName();
    double getPrice(); 
}

public class ShopInventory {

    private List<Product> products;

    public ShopInventory() {
        this.products = new ArrayList<>();
    }

    public void addProduct(Product product) {
        this.products.add(product);
    }

    public void removeProduct(Product product) {
        this.products.remove(product);
    }
}

The third-party store that we have just taken over holds GroceryItem‘s:

//third-party code
public class GroceryItem {

    String itemName;
    int costPerUnit;

   //constructor, getters and setters
}

Since our ShopInventory only holds items of type Product, let’s create an adapter for the newly introduced GroceryItem:

public class GroceryItemAdapter implements Product {

    private GroceryItem groceryItem;

    public GroceryItemAdapter(GroceryItem groceryItem) {
        this.groceryItem = groceryItem;
    }

    public String getName() {
        return groceryItem.getItemName();
    }

    public double getPrice() {
        return groceryItem.getCostPerUnit();    
    }
}

With that, we can now add both our regular products and the grocery items to our ShopInventory:

//code in our main method
ShopInventory inventory = new ShopInventory();

//adding regular store products - ones that implement Product interface
inventory.addProduct(new CosmeticProduct("Lavie Handbag", 5000.0));
inventory.addProduct(new FitnessProduct("Yoga SmartFit", 2000.75));


//adding GroceryItem to the store using an adapter
GroceryItem groceryItem = new GroceryItem("Wheat Flour", 100);
inventory.addProduct(new GroceryItemAdapter(groceryItem));

Conclusion:

The adapter pattern helps us to connect two incompatible interfaces exposing the same business functionality.

With an adapter pattern, we convert an existing interface to another interface that the client code expects.

One comment

hi, This is really very nice tutorial. it is very clearly given good examples to learn nicely. thanks for it.

Leave a Comment

Your email address will not be published. Required fields are marked *