Achieving Abstraction in Java with real world example
Abstraction is an important concept of Object oriented programming to help develop independent components and yet integrate them easily. In Java we can achieve it using Interface as well as abstract classes. Here we are going to explore with a real world example of how we can use Interface to achieve this.
As the name Interface implies, it is used for interconnecting/integrating two or more different applications/functionality without having to know what the internal implementation(abstraction) of those applications/functionalities.
To give an example, if you press a key ‘a’ in your computer keyboard, the letter a appears on screen. In order to display the letter ‘a’ in the screen, system may do thousands of tasks but for the user all he has to know is to press the button. Keyboard acts as an interface between you and the computer. User need not know what is actually happening inside the system.
Similarly in the software world, if you create a software that creates a PDF document, you want to have that software integrated with multiple other applications. Other applications do not have to know how you are actually generating the pdf. All they need to know is the method signature (name, return type and arguments) from your application to generate the PDF. Java Interfaces serve this exact purpose. It is also widely used when you have to do logical separation of multiple layers in the same application (ex: Business layer, Data access layer, Presentation layer, Services Layer etc.).
Basic characteristics of an Interface:
- It is a collection of methods and variables similar to a class with few unique characteristics.
- All methods and variables in interface are public by default.
- All variables in the interface are static and final.
- Interface does not contain constructors. Thus, cannot be initialized.
- All methods in interface are abstract.
- Starting java 8, we can provide a default implementation of a method.
- Starting java 8, we can have static methods in interface. But these methods are not inherited.
- Starting java 9, we can have private methods as well in interface.
Unlike Inheritance in java where a class can extend only one class, it can implement multiple interfaces. A class implementing an interface should implement all methods in the interface except for the ones there are default implementations.
Lets see about interface with a real time use case.
I have to create an Oven and its functionality is to bake item provided to it. An Oven cannot bake everything. For it to bake, the item sent to Oven should be Bakeable. Oven can do lot of work internally to bake an item but it need not be known to the end user.
Here comes the Interface in action as described below.
I am creating an interface called Bakeable and its definition is as follows. It has the methods performPreHeat(), getTemperature()and cookingDuration().Usually for all food, we need to preheat the oven so I am creating a default definition of performPreHeat() method to return true.
import java.time.Duration;interface Bakeable {default Boolean performPreHeat() {return true;public abstract Duration cookingDuration();Integer getTemperature();}}
The method cookingDuration has the qualifiers public and abstract. Even though the method getTemperature() does not have any qualifiers, public and abstract are the default. It is optional to specify them.
Now I am creating a class Oven and its functionality is to bake any bakeable item.
import java.time.Duration;
public class Oven {public void bake(Bakeable bakeable) {turnOn();if(bakeable.performPreHeat())performPreheat();setTemperature(bakeable.getTemperature());wait(bakeable.cookingDuration());turnOff();System.out.println(“Baking complete!!”);}private void turnOn() {System.out.println(“Turning on the oven”);}private void performPreheat() {System.out.println(“Preheating the oven”);}private void setTemperature(Integer temperature) {System.out.println(“Setting the temperature to: “ + temperature);}private void wait(Duration duration) {System.out.println(“Waiting for “ + duration.toMinutes() + “ minutes”);}private void turnOff() {System.out.println(“Turning off the oven”);}}
Now once I have the oven created, any one should be able to use the oven. I will be providing the interface to other applications. We can sell the oven to a bakery or a diner. They can use the oven if they implement the interface.
Let’s say in the bakery they want to bake a Cake. All they have to do is to implement Bakeable and they can send Cake to the Oven. Different bakery can have different implementations.
Code snippet of class that implements the interface
import java.time.Duration;
public class Cake implements Bakeable{private Integer weight;public Cake(Integer weight) {this.weight = weight;}@Overridepublic Boolean performPreHeat() {return false;}@Overridepublic Integer getTemperature() {return 240;}@Overridepublic Duration cookingDuration() {if(weight < 100)return Duration.ofMinutes(10);if(weight < 500)return Duration.ofMinutes(30);if(weight < 750)return Duration.ofMinutes(45);return Duration.ofHours(1);}public void deliver() {boxing();System.out.println(“Cake delivered!”);}private void boxing() {System.out.println(“Cake boxed!”);}}
Here performPreHeat() method is optional to implement as it has default definition in interface. If you want to disable preheat, then you will have to provide a custom implementation.
Now let’s see how we can pass the Cake to the oven.
public class Bakery {public static void main(String args[]) {Bakeable cake = new Cake(300);Oven oven = new Oven();oven.bake(cake);cake.deliver();}}
//Output:
Turning on the oven
Preheating the oven
Setting the temperature to: 240
Waiting for 30 minutes
Turning off the oven
Baking complete!!
Cake boxed!
Cake delivered!
Here in the example above the Bakery will not know the internal implementation of the Oven and what it internally does for baking. Similarly, Oven will not know the implementation of Cake. Cake has methods like deliver, boxing which Oven is not aware of.
Abstraction Achieved !!
Thanks for reading this blog!!