Interface in OOP: Guide to Polymorphism and Callbacks

Interface in OOP: Guide to Polymorphism and Callbacks

Today we will be looking at one of the important topic in programming. Yes, from the title you are informed that we will be looking at interfaces. If you are familiar with them, it’s really great, it will be a revision. Also, you may provide any correction in comments below. But for beginners who want to understand polymorphism, callbacks and other use cases of interface. We will look into at Interface in OOP paradigm. I have used JAVA here but the concept is same for every language out there. The only difference being the syntax of the programming language.

NOTE: I have used Java here because I am comfortable with Java. If you are not familiar with java you can still go through it. Because this post is not abut language but the concept.

Reviewing OOP

Object Oriented Programming (OOP) is the one among many paradigms on programming. This is one used among other paradigms such as Functional Programming. There are three main principles while programming in OOP. They are:

1. Encapsulation
2. Abstraction
3. Inheritance
4. Polymorphism

OOP cannot simply be explained into a simple blog post. If you really want to explore the depth of OOP, you should read multiple books. Here, I will provide a brief explanation about Polymorphism only. Why you ask ? It is because the main focus of this post isn’t OOP but a portion of it. I might cover up OOP in a different post in future. For now let us stick to our subject Polymorphism and Interface in OOP.

Polymorphism in OOP

Let us first consume the word in literal sense in English language. If we break down the word we will be left with Poly meaning many and Morph meaning form. So, we can understand the concept of polymorphism as converting one form in OOP to multiple forms without having to change anything in general.

The technical definition will be something entirely different. But here we are trying to practically understand what how Polymorphism can be leveraged. And how we can use it to our benefit in our code-base to make things easier for us.

Also Read: Learning about encrypting files & folders on Ubuntu

TECHENUM

The problem and the solution

The process of development is nothing but a series of steps to solve a particular problem. And the problem can be anything. It might be something really simple such as counting number of letters in a sentence to counting number of active flights in an Air Traffic Controller’s office.

We have had too much with one more analogy. Lets dive right in to the problem and how polymorphism solves it. In our hypothetical game let us assume we have a creature named Multivore. This creature can do anything imaginable and unimaginable. Let us say it can change forms and become Human, Horse, Donkey, etc.

As we can see Human and Horse have common operation but different ways of doing those things. Both animals eat but eat differently, walk but differently and so on. In real world this will not cause any issue. But when developing you cannot mix different type of objects into a single data structure. And this might not be true for JavaScript but strict programming languages do not allow this. This is where Polymorphism comes in, interfaces specifically.

We can bind multiple implementation to an interface to achieve this. We might argue that inheritance might solve this issue but there is a problem. Inheritance provides a common implementation for multiple things. The child must do everything the parent does with additional functions. I hope things are making sense. Let us see action of Interface in OOP.

About interfaces

Let us understand more about interfaces in OOP which will aid in understanding the concept of Polymorphism. Interface in layman’s terms is simply a contract. The contract will be fulfilled but the exact time is unknown.

In real world it is like saying: When I have Rs. 100,00 I will buy a new laptop. You see you have made a contract about buying a new laptop when you have Rs 100,00. But the problem is you don’t known when you will have that amount. You might have it after two days or after a year. But the goal is to buy new laptop once you have that amount.

That was a non technical explanation. Because to understand something we must break it down into something that we are familiar with. You might be wondering that this is a theory. How will I put it into code, well lets do this right away.

First create a interface OnMoneyGoalMet. This is to see when our targeted amount goal is reached.

public interface OnMoneyGoalMet { public void doBuyLaptop(); }

Now the usage of this might be something like below.

public class MyTodoList { private OnMoneyGoalMet onMoneyGoalMet; public void setOnMoneyGoalMet(OnMoneyGoalMet onMoneyGoalMet) { this.onMoneyGoalMet = onMoneyGoalMet } public void gatherMoney() { try { // let us assume 365 seconds is 1 year Thread.sleep(365_000) } catch(Exception exception){} // we have the money now we will go back and buy laptop onMoneyGoalMet.doBuyLaptop(); } }

Now we are just chilling in our home wondering about our to-do list. How that might look in code.

public class Home { public void doChill() { MyTodoList myTodoList = new MyTodoList(); myTodoList.setOnMoneyGoalMet(new OnMoneyGoalMet() { // we have already made a choice of store or laptop // if we have not ; do it and code it here. // once the money goal is met we this portion will be executed }); myTodoList.gatherMoney(); } }

In the above example while we are chilling at home we gather money and once the money gathering process is complete we buy the laptop. I hope that was easy to understand. Keep reading below to understand more.

A simple example

Let us look at one more example before proceeding but a different kind of example. It is about polymorphism and how we can achieve it using interfaces.

We will first create a simple Interface having that contains common operations.

public interface LivingThingsActionContract { public void eat(Food food); public void walk(float speed); public void doSpecialTrick(); }

After this we will use this to actually define how living things perform these actions. First lets take a look at Horse.

public class Horse implements LivingThingsActionContract { @Override public void eat(Food food) { // we will code on how the horse eats food.. // this is just an example so we will not be implementing how to achieve this } @Override public void walk(float speed) { // walk might be slow or fast depending on the state of horse } @Override public void doSpecialTrick() { // the horse might do something special } }

Now for Humans we might have something entirely different. Let us look at the example below.

public class Human implements LivingThingsActionContract { @Override public void eat(Food food) { // we will code on how the humans eat food } @Override public void walk(float speed) { // walk of humans are generally not so fast but well we have the speed } @Override public void doSpecialTrick() { // might dance or something which the horse will not do on default } }

Now we arrive at the main part. The two classes Human and Horse are completely different and cannot be mixed together. But since we have used a common interface LivingThingsActionContract we can store them in a single data structure. Which is shown below.

For the sake of readability we will not be coding everything but the minimum required for understanding.

public class SpecialOperation { private ArrayList<LivingThingsActionContract> mThingsToBeOperatedOn; public void doAwesomeStuff() { // here we can access both Human and Horse with methods in LivingThingsActionContract but they will still do what they are required to do if(!mThingsToBeOperatedOn.isEmpty()) { // make every living thing walk with certain speed foreach(LivingThingsActionContract thing: mThingsToBeOperatedOn) { thing.walk(22.0f) // walks with hypothetical speed of 22.0 } } } public addLivingThing(LivingThingsActionContract livingThing) { // here you can pass both Human and Horse because of Polymorphism, not because of interface mThingsToBeOperatedOn.add(livingThing); } }

Of course, the above code will not work and has may compile time errors. But this is just a demonstration of how an interface can be used for Polymorphism. And I hope I made you understand this. Now we will move forward to understand callbacks using interface in OOP.

Also Read: Image that crashes Android devices on wallpaper change

TECHENUM

Callback: What is it ?

After the basic understanding of polymorphism we have arrived at the most common topic used in OOP. The CALLBACK, most people dread them because of the fact that code looks messy. But this is no reason to overlook on how flexible and simple they are. Once you understand what callbacks are and how they work. You will understand why you need to use them.

You may have needed it but didn’t know the term callback. I was really surprised when I found out about CALLBACK. I was really excited and the felt I discovered something really amazing. The truth was entirely different I was just avoiding this topic of polymorphism altogether. Let me explain about callback in brief before you find the pattern.

Do you remember the click listeners on buttons ? Or any other components. Yes this is an example of callback. Callbacks are nothing but the block of code that is promised to be executed sometime in future. The developer doesn’t know about when it might happen but the developer is sure it will happen. How can the developer be sure ? Good question. It is because of the requirement of application.

Hypothetically, If you’re building an online attendance system. There will be a button which will facilitate the attendance. But, can you guess when the user will click the button ? The likely answer is NO. Not only click listeners but also the online operations such as uploading files and other things. If the file is large it will take some time. Using callbacks can be useful to known if the operation completed successfully or with an error.

Are you excited enough ? Lets jump right in on implementing our own callback.

Implementing our own callback

This is an example sample code which will not work directly. I have used this only as a reference hoping you will get the idea. We will create a simple callback to notify us about a long running operation. Let us assume encrypting a large file.

We will create a interface with name OnOperationCompleteListener.

public interface OnOperationCompleteListener { public onSuccess(); public onFailure(); }

After that we will assume we are doing some long learning task in LongRunningTask class.

public class LongRunningTask { private OnOperationCompleteListener onOperationCompleteListener; /** * This will set the listener to get update about task which will be in future. */ public void setOnOperationCompleteListener(OnOperationCompleteListener onOperationCompleteListener) { this.onOperationCompleteListener = onOperationCompleteListener; } public void encryptFile(String path) { HandlerThread ht = new HandlerThread("Example"); ht.start(); Handler handler = new Handler(ht.getLooper()); handler.post(new Runnable() { @Override public void run() { try { Thread.sleep(10_000); } catch (Exception ignore){ onOperationCompleteListener.onFailure(); } // we will reach here only after 10 seconds // notify the listeners about the operation complete staus. onOperationCompleteListener.onSuccess(); } }); } }

And we will hopefully use this code somewhere in our code base. Let us see the example below to get a better understanding.

public class Test { public static void main(String[] args) { LongRunningTask longRunningTask = new LongRunningTask(); // create a new instance of our listener OnOperationCompleteListener listener = new OnOperationCompleteListener() { @Override public void onSuccess() { // do something here ; put your code here to do something when the operation completes successfully } @Override public void onFailure() { // do something here ; put your code here to do something when the operation fails } } // we should set listener first before starting the actual operation. longRunningTask.setOnOperationCompleteListener(listener); // finally start the operation longRunningTask.encryptFile("path/to/your/file.extension"); } }

This is how you might create callbacks by using interface in OOP.

What next ?

We have learned two things in this post. A possible way to leverage basic Polymorphism. And, how to create callbacks and use it for our benefit. But you still might be confused about both the things. Make sure to google about these topics to gain much more information.

You should never limit yourself when exploring about new topics. But only exploring isn’t a practical way to retain the information. You have to practice multiple times to get the working ideas. Happy coding, keep learning.

Also Read: How to learn programming and where to start ?

TECHENUM

Naveen Niraula

I am an Android Developer. I really love to write tutorials and reviews about latest technologies.

Leave a Reply