How to implement Adapter pattern in Java?

Photo by Soonios Pro on Pexels.com

Let’s say you love nuts.

You buy them every now and then from a vendor named Raghav.

You buy it online through a java program which calls Raghav’s shop API.

Let’s say you have created a Shop interface to represent Raghav’s shop and created a class RaghavShop implementing it.

And you have declared a method orderNuts() in the interface which is implemented by RaghavShop class.

Every time you need nuts you make a call : shop.orderNuts() and you are delivered your nuts at your home.

Things are going fine. You are ordering once a week from his shop.

And then suddenly one day he closes his shop forever.

You immediately look for another shop and come to know about a vendor named Sachin.

The only problem with buying from him is that he has a different API .

His shop doesn’t implement the interface ‘Shop’ and he uses a different method ‘buyNuts’ and also he returns the Nuts using a different model object ‘SachinNuts’ instead of ‘Nuts’.

And still you dont want to change your client code.

You are still going to call orderNuts() on a ‘Shop’ object and you expect it to return ‘Nuts’ object

And so you delegate the final call to another class , an adaptor named ‘NutsShopAdapter’.

You call orderNuts() on the adapter class and the adapter in turn calls ‘buyNuts’ on ‘SachinNutsShop’ . The return object ‘SachinNuts’ is then converted to ‘Nuts’ using another adaptor class ‘NutsAdapter’.

Thats it.

You stick to your guns and go on calling orderNuts() on a ‘Shop’ object.

Back to your good old routine.

Here is the final client code :

package structural.adapter.pattern;

public class Client {

	public static void main(String a[]) {

		System.out.println("Ordering at Raghav Nuts Shop");
		
		Nuts nutsOriginal = orderNuts(new RaghavNutsShop());

		System.out.println(nutsOriginal);

		
		System.out.println("Ordering at Sachin Nuts Shop");
		
		Nuts nutsNew = orderNuts(new NutsShopAdapter(new SachinNutsShop()));

		System.out.println(nutsNew);

	}

	private static Nuts orderNuts(Shop shop) {

		return shop.orderNuts("Pista", "100");

	}

}

As you see initially you are ordering nuts at RaghavNutsShop.

You want 100 grams of Pista.

The method invoked is shop.orderNuts() and it remains the same in the next call as well.

Here you are passing an instance of NutsShopAdapter instead of an instance of RaghavNutsShop .

The adapter class takes an instance of SachinNutsShop in its constructor.

Now lets look at the adapter class:

package structural.adapter.pattern;

public class NutsShopAdapter implements Shop {

	SachinNutsShop sachinNutsShop;

	public NutsShopAdapter(SachinNutsShop sachinNutsShop) {

		this.sachinNutsShop = sachinNutsShop;
	}

	@Override
	public Nuts orderNuts(String name, String quantity) {

		SachinNuts sachinNuts = sachinNutsShop.buyNuts(name, quantity);

		Nuts nuts = new NutsAdapter(sachinNuts);

		return nuts;

	}

}

It uses the same interface ‘Shop’ and defines the same method ‘orderNuts’.

But inside the orderNuts method it invokes buyNuts() method of SachinNutsShop (the instance of which was passed to its constructor earlier).

And then since SachinNutsShop returns ‘SachinNuts’ we use one more adapter class ‘NutsAdapter’ which converts ‘SachinNuts’ to ‘Nuts’.

Here is the NutsAdapter:

package structural.adapter.pattern;

public class NutsAdapter extends Nuts {

	SachinNuts sachinNuts;

	public NutsAdapter(SachinNuts sachinNuts) {

		this.sachinNuts = sachinNuts;
	}

	@Override
	public String getName() {

		return sachinNuts.getNutsName();
	}

	@Override
	public String getQuantity() {
		return sachinNuts.getQuantityInGrams();
	}

	@Override
	public String toString() {

		return "Name=" + sachinNuts.getNutsName() + "-Quantity: " + sachinNuts.getQuantityInGrams();
	}

}

The Getter methods and toString() method are overridden to return values obtained from SachinNuts object.

Here is the SachinNutsShop class , the adaptee:

package structural.adapter.pattern;

public class SachinNutsShop {
	
	
	SachinNuts buyNuts(String nutsName,String quantity) {
		
		
		SachinNuts nuts = new SachinNuts();
		nuts.setNutsName(nutsName);

		nuts.setQuantityInGrams(quantity);
		
		return nuts;
	}

}

Here is their model object ‘SachinNuts’:

package structural.adapter.pattern;

public class SachinNuts {
	
	String nutsName;
	
	String quantityInGrams;

	public String getNutsName() {
		return nutsName;
	}

	public void setNutsName(String nutsName) {
		this.nutsName = nutsName;
	}

	public String getQuantityInGrams() {
		return quantityInGrams;
	}

	public void setQuantityInGrams(String quantityInGrams) {
		this.quantityInGrams = quantityInGrams;
	}
	
	

}

Here is the Shop interface which you had been using before :

package structural.adapter.pattern;

public interface Shop {
	
	Nuts orderNuts(String name,String quantity);

}

And RaghavNutsShop had followed this :

package structural.adapter.pattern;

public class RaghavNutsShop implements Shop{

	@Override
	public Nuts orderNuts(String name, String quantity) {
		
		System.out.println("Sorry we are closed");
		return null;
	}

}

Before they had closed it ofcourse.

Here is the output of client code :

Ordering at Raghav Nuts Shop
Sorry we are closed
null
Ordering at Sachin Nuts Shop
Name=Pista-Quantity: 100

Sachin Nuts Shop is delivering nuts!

Quoting Gang of Four:

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

Here is the code :

https://github.com/vijaysrj/designPatternsGoF/tree/master/src/structural/adapter/pattern


Posted

in

,

by

Comments

Leave a Reply

Discover more from The Full Stack Developer

Subscribe now to keep reading and get access to the full archive.

Continue reading