DEV Community

Jules Roadknight
Jules Roadknight

Posted on

Interfaces Explained

In the quest to write Better Code, you will encounter many abstract concepts, the explanations of which are themselves often abstract. The idea of an Interface is a simple one when kept grounded in code, so that's how I'm addressing it here.

Below is an interface in a Contact Manager I've been making in Java. It's a command-line application that stores information in memory. Instead of class it says interface, its methods have no body, and it contains no variables, although it can have final static fields.

Example 1

interface InputOutput {

    void display(String message);

    String confirmInput(String field, boolean isAnUpdate);

    int getNumberInput();

    String getInput(String detail);

}
Enter fullscreen mode Exit fullscreen mode

What does an Interface do?

Nothing. It's just a blueprint that you must adhere to.

If I were to remove it and all mentions of it from my project, nothing would change. This isn't surprising, as the four methods it contains have no body. Because they're abstract/blueprint methods.

However, since my ConsoleIO class (see Example 2) 'implements InputOutput', it must contain the methods that the InputOutput interface contains. In other words, we're stating that InputOutput was used as a model around which the ConsoleIO class was made.

It could also contain methods not specified in the interface, but it has to have those core ones.

Example 2 shows the class that the InputOutput interface was modelled after (in this case, I made the class and extracted an interface after, but in the future I might start with an interface). It contains the same four methods, as well its own instance method and some variables. The difference is that the methods have bodies now, implementing details of the relevant functionality however I see fit.

Example 2

public class ConsoleIO implements InputOutput {

private final InputStream input;
private final OutputStream output;
private final BufferedReader reader;
public final PrintStream printer;

public ConsoleIO(InputStream input, OutputStream output) {
    reader = new BufferedReader(new InputStreamReader(input));
    printer = new PrintStream(output);
    this.input = input;
    this.output = output;
}

public void display(String message) {
    printer.println(message);
}

public String confirmInput(String field, boolean isAnUpdate) {
    Boolean validInput = false;
    String userInput = null;
    while (!validInput) {
        userInput = getInput(field);
        validInput = ValidateInput.validateInput(field, userInput, isAnUpdate);
    }
    return userInput;
}

public int getNumberInput() {
    String userInput;
    try {
         userInput = reader.readLine();
    } catch (IOException e) {
        return - 1;
    }
    try {
        return Integer.parseInt(userInput);
    } catch (NumberFormatException e) {
        return 0;
    }
}

public String getInput(String detail) {
    display("Please enter your " + detail + ":");
    String userInput = null;
    try {
        userInput = reader.readLine();
    } catch (IOException e) {
        display("Cannot read line" + e);
    }
    return userInput;
}
}
Enter fullscreen mode Exit fullscreen mode

Let's Get Abstract

An interface doesn't handle anything concrete. It doesn't specify how the methods it contains are to be implemented, only that they should exist.

The interface is a plan for future classes that will implement the same functionality in a different context.
In this case, it's an InputOutput interface, so if in the future I add a class to my program so that it works online as well as in the command-line, it will need methods to:

  1. Display output
  2. Confirm input
  3. Get string input
  4. Get menu input

Polymorphism

Example 3

interface Save {
   void saveNumber(String phoneNumber)
}

class File implements Save
    public void saveNumber(String phoneNumber) {
        // However you implement saving to a file
    }
}

class Database implements Save
    public void saveNumber(String phoneNumber) {
        // However you implement saving to a database
    }
}
Enter fullscreen mode Exit fullscreen mode

Interfaces help create systems that implement polymorphism. The idea of polymorphism is that classes are interchangeable, so swapping an instance of class File for one of Database wouldn't matter, as they have the same methods.

Let's say Phonebook calls the write method for either of these, injecting the relevant class as destination.

destination.saveNumber("5550123");
Enter fullscreen mode Exit fullscreen mode

It would work either way, and the program wouldn't know or care where it's saving to.

Closing

Interfaces are abstract because they serve as plans or reminders rather than having any real functionality. Languages like Ruby don't even have interfaces, but it helps to keep the idea of them in your mind when designing your system.

Top comments (0)