Language: EN

que-son-los-interfaces-en-programacion

What are and how to use interfaces

In object-oriented programming, an interface is a declaration that defines a set of methods that classes can later implement.

If a class implements all the methods of the interface, we say that the class implements or fulfills that interface (if there is even one method that the class does not have, then it does not implement the interface).

Interfaces define a set of functionalities without specifying how they should be implemented. They only declare the method signatures, leaving their implementation to the classes.

In this way, interfaces provide a very high level of abstraction, as they allow defining what a class can do, without defining how they do it at all.

Since they are one of the most important points of object-oriented programming, the highest expression of Polymorphism, a better invention than donuts, and at the same time one of the concepts that are hardest to understand, here comes a daily example! 👇

Purpose of interfaces

Imagine that tomorrow you have to make a very important trip. You know how to drive, but you don’t have a car. But that’s okay, your boss tells you:

- Tomorrow I’m going to leave a rental vehicle at your door.

You go to sleep more peacefully. But suddenly you think “wait a minute… did he say a vehicle? What vehicle? Is he going to leave me a helicopter? Or a submarine??!”

Sure, because you know how to drive cars. But you have no idea how to drive helicopters, submarines, or ostriches.

interface

Your boss, the nice guy, left you a helicopter.

The problem is that your boss told you he would leave an object at the door, but you have no idea if you’ll know how to use it. Well, your methods have the same issue with your objects.

One way to solve this is to use an abstract class Car. If your boss tells you he’s going to leave you a rental car, there’s no problem because you know how to drive.

But another way to do it is if your boss tells you:

- Tomorrow I’m going to leave you something with pedals and a steering wheel that can be driven.

Alright, you really should start looking for another job because your boss is very strange. But still, you sleep peacefully. Because he’s going to leave you something that can be driven. And you (again) know how to drive.

In fact, this way is much more versatile. Because he can not only give you a car. He can leave you a small van, a tractor, or a carnival float… but you will be able to drive it. Because 🌟 —> you know how to drive <— 🌟.

(Yes, I have been repetitive with “you know how to drive”. We’ll see why in the next section 👇)

Practical case

Let’s see if we can translate what we explained earlier into programming terms. What we were saying is that you are a Driver. And drivers have a method that allows them to Drive(...).

class Driver
{
	Drive(... something ... );
}

What can you drive? Well, one of the alternatives is to say that you can drive Cars. Which would look like this.

class Driver
{
	Drive(Car car);
}

But I’ve repeated so much about “you know how to drive”. Your method does not know how to drive cars, but “anything that can be driven”. It doesn’t matter if it’s a car, a van, or a carnival float.

So now we can be much more general. What transferred to the coding world looks like this:

class IDrivable 
{
	PressPedals(),
	TurnSteeringWheel(),
	// whatever else is needed
}

class Car implements IDrivable
class Van implements IDrivable
class Float implements IDrivable

class Driver
{
	Drive(IDrivable drivable);
}

Now your driver can drive “anything that can be driven”. This includes cars, vans, and even (I love saying it) carnival floats.

For this, the only condition is that they must be IDrivable. Which means they need to have pedals, a steering wheel, and (whatever else is needed, it’s just an example).

Interfaces are usually prefixed with an ‘I’ at the beginning.
For example: IDrivable, IFlyable, IPayable…

Interface in programming

It is often used to explain interfaces as a “contract” that a class can fulfill. This can be helpful to understand the concept, but honestly, I don’t particularly like this explanation.

An interface is called an interface because it literally is an interface. What is the interface of a machine? The elements, or devices, or programs that you use to interact with it.

In the case of programming, it’s the same,

An interface is the declaration of a way to interact with a class.

This comes from a revelation you will have at some point (I hope it’s now) Why does a method need to receive a class? To do things with it. But… what things?

Well, most of the time a method receives an object to do this:

void MyFunction(MyObject obj)
{
	obj.MyVariable = 35;
	obj.MyMethod("invented_parameter");
}

That is, the vast majority of methods receive an object simply to do . and then whatever (.MyVariable, .MyMethod(...)).

And for that, the vast majority of methods do not need an object of type MyObject. They work just as well knowing its interface.

interface IMyInterface 
{
	string MyVariable,
	void MyMethod(string),
}

MyObject implements IMyInterface

void MyFunction(IMyInterface obj)
{
	obj.MyVariable = 35;
	obj.MyMethod("invented_parameter");
}

Because all they need to know is that what they have has the variable .MyVariable, and the method .MyMethod(...) available.

Comparison with abstract classes

An interface is similar to an abstract class in that it defines a set of methods that must be implemented by the classes that use it. In fact, an interface is like a “!!ultimate abstract superclass!!“.

But fundamentally, they have very important differences, both in functionality and in concept.

In terms of functionality, the abstract class can contain implementations of some methods. In fact, this is its main utility, to provide a base. In contrast, an interface is always fully abstract.

In terms of concept, the abstract class implies a relationship of inheritance, and an interface implies implementation. More details in the next point 👇.

When to use inheritance and when to use an interface

Another question that will often arise is when you should use an interface and when to use inheritance (it doesn’t matter if it’s an abstract class or not).

Sometimes you’ll get confused because they seem similar, but in reality, they are two totally different things. Inheritance means belonging, and an interface means behavior.

It’s somewhat difficult to explain, so I’ll give you a good trick that will help you differentiate one from the other (and at the same time understand the concept)

  • It’s inheritance if you can say is a
  • It’s an interface if you can say can / is able to

Let’s see it with two examples:

Inheritance example

A van is a vehicle

A car is a vehicle

Then there is a relationship of inheritance (belonging). van and car are derived classes, and vehicle is a base class.

Interface example

A van can be driven

A bird can fly

These are implementation relationships (behavior), with IDrivable or IFlyable.

Examples in different languages

Let’s see how different languages implement the concept of interfaces.

In C#, interfaces are declared with the reserved word interface.

public interface IAnimal
{
    void MakeSound();
}

public class Dog : IAnimal
{
    public void MakeSound()
    {
        Console.WriteLine("Woof");
    }
}

public class Cat : IAnimal
{
    public void MakeSound()
    {
        Console.WriteLine("Meow");
    }
}

// Usage
IAnimal dog = new Dog();
IAnimal cat = new Cat();

dog.MakeSound(); // Output: Woof
cat.MakeSound();  // Output: Meow

In C++, interfaces are achieved through abstract classes with at least one pure virtual function.

#include <iostream>

class IAnimal {
public:
    virtual void MakeSound() const = 0;
    virtual ~IAnimal() = default;
};

class Dog : public IAnimal {
public:
    void MakeSound() const override {
        std::cout << "Woof" << std::endl;
    }
};

class Cat : public IAnimal {
public:
    void MakeSound() const override {
        std::cout << "Meow" << std::endl;
    }
};

// Usage
int main() {
    IAnimal* dog = new Dog();
    IAnimal* cat = new Cat();

    dog->MakeSound(); // Output: Woof
    cat->MakeSound();  // Output: Meow

    delete dog;
    delete cat;

    return 0;
}

In JavaScript, there is no native syntax to define interfaces as in other languages. However, we could achieve similar behavior using abstract classes or simply using objects that share a common set of methods.

// We define an object that acts as an "interface" in JavaScript
const IAnimal = {
    makeSound: function() {
        throw new Error("makeSound method not implemented");
    }
};

// Implementation of the Dog class
class Dog {
    makeSound() {
        console.log("Woof");
    }
}

// Implementation of the Cat class
class Cat {
    makeSound() {
        console.log("Meow");
    }
}

// Usage
const dog = new Dog();
const cat = new Cat();

dog.makeSound(); // Output: Woof
cat.makeSound();  // Output: Meow

In TypeScript, interfaces are defined using the reserved word interface.

interface IAnimal {
    makeSound(): void;
}

class Dog implements IAnimal {
    makeSound(): void {
        console.log("Woof");
    }
}

class Cat implements IAnimal {
    makeSound(): void {
        console.log("Meow");
    }
}

// Usage
const dog: IAnimal = new Dog();
const cat: IAnimal = new Cat();

dog.makeSound(); // Output: Woof
cat.makeSound();  // Output: Meow

In Python, interfaces are achieved through abstract classes using the abc module.

from abc import ABC, abstractmethod

class IAnimal(ABC):
    @abstractmethod
    def make_sound(self):
        pass

class Dog(IAnimal):
    def make_sound(self):
        print("Woof")

class Cat(IAnimal):
    def make_sound(self):
        print("Meow")

# Usage
dog = Dog()
cat = Cat()

dog.make_sound() # Output: Woof
cat.make_sound()  # Output: Meow

Best practices Tips

Interfaces are one of the best tools to keep our program clean. They allow us to reduce class coupling, which we already know is one of the main problems of OOP.

They also favor code reuse, promote abstraction, reduce inheritance between classes… in short, a wonder. Let’s use them!

But (in this life, there is always a but) you have to know how to use them. The main problem you will have is when to use an interface and when to use inheritance. We’ve seen this in a previous point.

On the other hand, the other difficulty will be how to define an interface. For that, let’s remember that an interface models behaviors, not entities.

For example, you will be very tempted to make an interface for everything. Every class ends up having an interface. You have a User class, and it has its IUser. You have a ShoppingCart class and you make its interface IShoppingCart.

We have all done that, and you will do it too at some point. But in reality, making an interface for every class, you are “killing” half the fun of interfaces. Interfaces should model behavior. So in the case of User, you will have IIdentifiable, IEmailable, or things like that.

But of course, if I don’t separate the interfaces, I end up violating the principle of interface segregation, with interfaces that have too many methods. But if I separate them too much, I end up almost in duck typing.

So where do I separate? There is no magic recipe. It will vary depending on your object model, your experience, what your body asks for… and even then, sometimes you will make the wrong call (but that’s okay, it can be refactored and that’s it).