Core Java

Java Adapter Design Pattern Example

1. Introduction to design patterns

A design pattern in Java is a defined implementation pattern for developing classes and objects. A design pattern provided the base to develop an architecture that reduces redundancy in the code and improves the manageability. There are numerous design patterns defined in Java. They are primarily categorised in the below categories:

  • Creational design patterns: The design pattern defined to manage the instantiation of the object
  • Structural design patterns: The design pattern defined to build a structure using classes to make coding simpler and manageable
  • Behavioural design patterns: The design pattern defined to manage the interactions between different objects.

You can also check a tutorial in the following video:

Java Design Patterns Tutorial – video

Of these, we are going to discuss one of the structural design patterns – Adapter design pattern. Adapter, as the name suggests, is a class that helps in implementing variations of another class. This concept is based on the electronic adapters that help in converting the electric voltages to different voltage. Such a pattern is used where there are multiple variations of a single item or class possible. For instance, consider a grocery item – Flour bag. The flour bag can come in multiple sizes and each would have a different price. We would further understand the same concept with code based example.

2. Understanding Java Adapter Design Pattern

Before proceeding into the technicals of the adapter design patterns, let us first functionally understand what an adapter design pattern is. In order to understand the adapter pattern, we will be using the analogy of the domain from where these words have been picked up. The electrical supply is the source of these terminologies.

An adapter in electrical supply is a converter that will basically provide you the required voltage by converting the electrical supply voltage into the variation of voltage as needed. The adapter fits into the electrical socket that is in turn connected to the electric supply. Thus, the source entity over here is the electrical supply. The socket is a object that helps the adapter to connect to the source entity. Thus, the source provides the default variant of the main entity – electricity here. An analogy of the concept discussed above is shown below

Java Adapter Design Pattern - Adapter Pattern
Adapter Pattern

As it can be seen in the analogy above, the Adaptee is the socket, the adapter is the class doing the task of providing voltage as per the client’s need. Thus, here the adaptee is called the socket that is directly connected to the source of electricity. The adapter does the job of taking in the default input(electricity) and providing a converted output. The final object “Client” consumes this variation provided by the adapter. In the technical sense, an adapter is used for variety of reasons. These reasons are discussed in depth below.

2.1 Project development & Adapter creation

Whenever an organisation develops a project, it is difficult for the organisation to take care of every client’s requirements. They develop the project such that a generic implementation of every functional entity is available. In the SaaS domain, the code provided to the client almost always requires certain variations in the entity. These variation are not possible to incorporate directly in the main code as the changes will apply to every client if applied.

As a solution to this, the organisation provides the client with a solution where in the client can use the default entities and classes to extend them. These classes are then further extended to obtain different variations of entities. Thus, it prevents redundancy in code when the developer requires certain variations of same entity. This implementation, where a default entity item is extended to obtain different variation of the same entity,  is called the Adapter pattern.

Thus, in the adapter pattern we create a class that takes the default object as an input in its functions and then returns a variation of the object. In this manner, the client receives the flexibility to modify the entities as per their need. Notice here that it is ultimately providing a way of structuring the code. This is the reason due to which we consider adapter pattern to be a structural design pattern.

3. Types of Adapter design pattern

There are two primary implementations in the adapter design pattern:

  1. Class adapter design pattern
  2. Object adapter design pattern

The Class adapter design pattern involves extending a class acting as socket and implementing an adapter. However, in the object adapter pattern, we implement the adapter interface and use a socket class object to create consequent objects. Let us now understand this concept in detail using the example of Flour bag.

3.1 Class adapter design pattern

Consider a class Flour with two attributes – weight and price as shown in the code below.

Flour.java

package com.javacodegeeks.abk;

public class Flour {
	int weight;
	float price;
	
	public Flour(){
		
	}
	public Flour(int weight,float price) {
		this.weight = weight;
		this.price = price;
	}
	public int getWeight() {
		return weight;
	}
	public void setWeight(int weight) {
		this.weight = weight;
	}
	public float getPrice() {
		return price;
	}
	public void setPrice(float price) {
		this.price = price;
	}

}

The above class is the starting point of the design. It can be considered as the electric supply in the adapter analogy. The next step is to create a provider of this item. By default, every electric socket provides a certain fixed output. In the same way, our next class will provide us a socket like function that outputs a default sized and default priced Flour item.

FlourItem.java

package com.javacodegeeks.abk;

public class FlourItem {
	public Flour getFlourItem() {
		return new Flour(10,1000);
	}
}

As it can be seen, the above class provides a function to get the object of Flour class with default values. Thus, it is a medium to get a pre-initialised default object. However, the item could be available in variety of sizes. This makes it necessary to create a class that delivers variations of this object. However, if a class with fixed values is supplied, changing the values externally would not be possible. Hence, the adapter design pattern suggests that we provide an interface that should be implemented by the relevant classes. This is similar to defining the output voltages that would be required for different devices. For instance, there can be 5V, 9V, 12V adapters each providing a different converted voltage output. Each of these voltages are defined but their method of creation might differ so would their implementation. Hence, we create an interface as shown below:

FlourInterface.java

package com.javacodegeeks.abk;

public interface FlourItemInterface {
	public Flour getQuintal();
	
	public Flour get10kg();
	
	public Flour get1kg();
}

The above class contains 3 different methods to provide flour packets of 3 varying sizes. Now, we provide the user freedom to implement the class and set the relevant pricing. Additionally the implementing class will extend the socket class FlourItem that provides the default object. Thus, the code would appear to be similar to what has been shown below.

FlourItemImplementor.java

package com.javacodegeeks.abk;

public class FlourItemImplementor extends FlourItem implements FlourItemInterface {

	@Override
	public Flour getQuintal() {
		Flour f = getFlourItem();
		f.setPrice(f.getPrice()*10);
		f.setWeight(100);
		return f;
	}

	@Override
	public Flour get10kg() {
		Flour f = getFlourItem();
		return f;
	}

	@Override
	public Flour get1kg() {
		Flour f = getFlourItem();
		f.setPrice(f.getPrice()/10);
		f.setWeight(1);
		return f;
	}

}

The above code implements the three functions by specifying different prices for each packet. In this manner the adapter pattern helps to separate the attribute definitions and object variations structurally. This pattern is called the class adapter pattern because it uses the class FlourItem and extends its functionality. The other pattern – Object adapter pattern however uses the object of the relevant class to provide the adapter implementation. We would see the implementation of the same in the next section.

3.2 Object Adapter pattern

In the class adapter pattern, we implemented the interface containing the possible variations of the main class and extended the class that provided the default object. However, this unnecessarily extends the complete features which may or may not be expected. In such a case, to sort out this problem, we prefer to create the object of the default class or the socket level class. This object is then used in the implementor class to get the default object.

The object obtained from the socket level class is then utilised to modify and obtain the final object instance. This object instance is as per the expected output from the adapter level class. Thus, the adapter class does the job of providing the variations of the parent object without extending it directly.

A sample code of how the object adapter pattern is implemented, is shown below.

Flour.java

package com.javacodegeeks.abk;

public class Flour {
	int weight;
	float price;
	
	public Flour(){
		
	}
	public Flour(int weight,float price) {
		this.weight = weight;
		this.price = price;
	}
	public int getWeight() {
		return weight;
	}
	public void setWeight(int weight) {
		this.weight = weight;
	}
	public float getPrice() {
		return price;
	}
	public void setPrice(float price) {
		this.price = price;
	}

}

The above class is the starting point of the design. It can be considered as the electric supply in the adapter analogy. The next step is to create a provider of this item. By default, every electric socket provides a certain fixed output. In the same way, our next class will provide us a socket like function that outputs a default sized and default priced Flour item.

FlourItem.java

package com.javacodegeeks.abk;

public class FlourItem {
	public Flour getFlourItem() {
		return new Flour(10,1000);
	}
}

FlourInterface.java

package com.javacodegeeks.abk;

public interface FlourItemInterface {
	public Flour getQuintal();
	
	public Flour get10kg();
	
	public Flour get1kg();
}

FlourItemImplementor.java

package com.javacodegeeks.abk;

public class FlourItemImplementor implements FlourItemInterface {
	
	FlourItem fItem = new FlourItem();
	@Override
	public Flour getQuintal() {
		Flour f = fItem.getFlourItem();
		f.setPrice(f.getPrice()*10);
		f.setWeight(100);
		return f;
	}

	@Override
	public Flour get10kg() {
		Flour f = fItem.getFlourItem();
		return f;
	}

	@Override
	public Flour get1kg() {
		Flour f = fItem.getFlourItem();
		f.setPrice(f.getPrice()/10);
		f.setWeight(1);
		return f;
	}

}

As it can be seen in the above code, an object of the socket level class has been created and used to get the default object unlike directly extending the class.

4. Benefits of Adapter design pattern

As discussed above, the adapter design pattern is normally used for projects where the classes in the projects have defined variations. The adapter design patterns allows the developer to create a skeleton with provision to obtain each possible pre-defined variation. Alternatively, it also allows the client to create the adapter classes and utilise the socket level classes as per their requirements.

The adapter design has the below benefits:

  • It helps in reducing the code redundancy by providing the variation of the object pre-developed
  • It provides easier access to variations of objects using the adapter class methods
  • The memory utilisation is reduced as the processing necessary to create the variation of objects is reduced
  • It improves the maintainability of the code. It becomes easier to edit the variations of the objects
  • Reduced development time due to already manipulated objects available from the adapter class

5. Best situation to use Adapter pattern

Adapter pattern is mainly used to connect two unrelated interfaces together. An adapter pattern is preferred when we are expecting the entities to be expose in an environment where the changes will definitely be expected by the clients. In such scenarios, we should prefer an arrangement where either the developer or client could create a class that takes care of the variations.

The adapter pattern is best suited for use in the below situations:

  •  When you have a class ready to be exposed to the outside world but there are requirements where certain changes might be required in the values of attributes for default object.
  • You need a class that can be easily reused for several operations on the objects that might be needed frequently. In such a situation, the adapter class defines certain operations in advance and exposes them
  • There are too many subclasses that need to be created but that appears to be making code haywire. In such a situation, the adapter implements the interface of such classes to simplify the code implementation

6. Conclusion

The adapter design pattern provides a structural way of creating and developing classes. The adapter design pattern focuses on bringing common operations on an adapter that will be reused. This not only prevents the client from accessing unwanted methods but also prevents any unexpected variation of object from being used. Thus, adapter design pattern principle is widely used to conceal the core implementation of the entity class and reduce the effort in consuming the objects.

7. Download the Source Code

That was Java Adapter Design Pattern Example.

Download
You can download the full source code of this example here: Adapter Pattern.zip

Abhishek Kothari

Abhishek is a Web Developer with diverse skills across multiple Web development technologies. During his professional career, he has worked on numerous enterprise level applications and understood the technological architecture and complexities involved in making an exceptional project. His passion to share knowledge among the community through various mediums has led him towards being a Professional Online Trainer, Youtuber as well as Technical Content Writer.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button