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 subsequently implement.

If a class implements all the methods of the interface, we say that the class implements or fulfills that interface. If there is one method that the class does not have, then the class 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, since they allow defining what a class can do, without delving into defining how they do it.

As they are one of the most important points of object-oriented programming, the maximum expression of Polymorphism, better invention than donuts, and at the same time is one of the most difficult concepts 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 it’s fine, your boss tells you:

- Tomorrow I’m going to leave a rental car at the door

You go to sleep more peacefully. But suddenly you think “wait a moment… did he say a vehicle? What vehicle? Is he not 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, or submarines, or ostriches.

interface

Your boss, the funny one, has left you a helicopter

The problem is that your boss has told you that he is leaving an object at the door, but you have no idea if you are going to be able to use it. This is how your methods feel about your objects.

One way to solve this is to use an abstract class Car. If your boss tells you that he is going to leave a rental car, then there is 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 a thing with pedals and steering wheels that can be driven

Okay, you should really start looking for another job because your boss is very weird. But, you sleep peacefully again. 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 it can not only give you a car. It can leave you a small van, a tractor, or a carnival float… but you’re going to be able to drive it. Because 🌟 —> you know how to drive <— 🌟.

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

Practical case

Let’s see if we translate what we explained before in the previous point to the equivalent in programming. 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 alternative is to say that you can drive Cars. Which would be this.

class Driver
{
	Drive(Car car);
}

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

So now we can be much more general. What translated to the code world is this:

class IDrivable 
{
	PushPedals(),
	TurnSteeringWheel(),
	// whatever else was 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 are IDrivable. Which means, they have to have pedals, a steering wheel and (whatever else is needed, it’s an example).

Interfaces are usually denoted with an ‘I’ at the beginning.
For example: IDrivable, IFlyer, IPayer…

Interface in programming

It is often used to explain interfaces that are like a “contract” that a class can fulfill. It may be useful to understand the concept, but the truth is, I don’t particularly like this explanation.

An interface is called an interface because, literally, it 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 that 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 object)
{
	object.MyVariable = 35;
	object.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 are just as good with knowing their interface.

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

MyObject implements IMyInterface

void MyFunction(IMyInterface object)
{
	object.MyVariable = 35;
	object.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 the sense that it defines a set of methods that must be implemented by the classes that use it. In fact, an interface is like a “super ultimate abstract class!!“.

But 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, providing a base. By contrast, an interface is always fully abstract.

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

When to use inheritance and when to use interfaces

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

Sometimes you will get confused because they seem similar, but they are actually two completely different things. Inheritance means belonging, and the interface means behavior.

It’s difficult to explain, so I’ll give you a good trick, which will help you to differentiate one from the other (and by the way, understand the concept)

It is inheritance if you can say “it is a”

It is an interface if you can say “can / can be”

Let’s see it with two examples:

Example of inheritance

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 examples

A van can be driven

A bird can fly

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

Examples in different languages

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

In C#, interfaces are declared with the keyword 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 using 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.

// 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 keyword 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 using 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 maintain the cleanliness of our program. They allow us to reduce the coupling of classes, which we already know is one of the main problems of OOP.

They also favor code reuse, promote abstraction, reduce inheritance between classes… well, a wonder. Use them!

Buuuuut (there’s always a but in this life) 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 already seen this in a previous point.

On the other hand, the other difficulty will be how to define an interface. To do that, remember that an interface models behavior, not entities.

For example, you will be very tempted to create 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’ve all done that, and you will too at some point. But in reality, by making an interface per class, you are “ruining” half the grace of the 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 breaking the principle of interface segregation, with interfaces with too many methods. But if I separate them too much, I end up almost in duck typing.

So, where do I separate them? Well, there’s no magic recipe. It will vary depending on your object model, your experience, what your body asks for… and even then, sometimes you’ll make the change (well, no problem, it’s refactored and done).