Interfaces

How do we define what an object can do without caring how it does it? Master Interfaces to build modular and swappable code.

April 24, 20264 min read11 / 14

In our journey through OOP, we've used classes as blueprints. But sometimes, a blueprint is too specific. Sometimes, you just need a Contract. That contract is called an Interface.

The Essentials

The "Contractual" guide:

  1. Pure Behavior: Interfaces only define What an object can do, not How it does it.
  2. Multiple Implementation: A single class can follow many different contracts (implement multiple interfaces).
  3. Decoupling: High-level code can depend on an interface instead of a specific class, making parts of your system "swappable."
  4. No State: Interfaces cannot store data (attributes); they only hold method signatures.

The USB Analogy

Think about the USB port on your laptop.

  1. The Contract: The USB standard is an interface. It says: "If you want to connect to this port, you must have this specific shape and speak this specific data language."
  2. The Implementations: You can plug in a Mouse, a Keyboard, a Webcam, or a Hard Drive.
  3. The Laptop's Perspective: The laptop doesn't care what is plugged in. It only cares that the device follows the "USB Contract."

This is the magic of Interfaces. They allow you to plug new logic into your system without changing the system itself.

Interfaces in Action: The Behavioral Contract

Rigid Inheritance

If you use inheritance for behavior, you get stuck. A class can only have one parent. What if a Duck needs to Fly AND Swim?

class Bird { fly() { .. } }
class Fish { swim() { .. } }

class Duck extends Bird {
  // How do I also get swim()?
}

Inheritance represents "What it IS." It is too restrictive for shared behaviors.

Flexible Interfaces

Interfaces represent "What it CAN DO." A class can implement as many "abilities" as it needs.

interface Flyable { fly(); }
interface Swimmable { swim(); }

class Duck implements Flyable, Swimmable {
  fly() { .. }
  swim() { .. }
}

Now the Duck can have multiple behaviors without the "Diamond Problem" of multiple inheritance.

Code Implementation: The Handshake Contract

Here is how you define and implement a behavioral contract:

interface Swimmable { swim(): void; } class Human implements Swimmable { swim() { console.log("Swimming with a freestyle stroke!"); } } class Boat implements Swimmable { swim() { console.log("Propelling through water with an engine!"); } } // The function doesn't care WHAT the object is, only that it can SWIM. function rescueInWater(object: Swimmable) { object.swim(); } rescueInWater(new Human()); rescueInWater(new Boat());

Why Use Interfaces Over Inheritance?

  1. Multiple "Abilities": A Duck is an Animal (Inheritance), but it can also Fly and Swim (Interfaces). In Java, a class can only have one parent, but it can have many abilities.
  2. Looser Connection: Inheritance is a very strong bond. Interfaces are a light "handshake." Use interfaces for behaviors that are shared across unrelated classes.

By mastering interfaces, you move from building "monoliths" to building modular, "Lego-like" systems where components can be swapped and upgraded with ease.

Now that we know how to define pure behavior, let's learn about the middle ground: Abstract Classes.

Practice what you just read.

Interfaces: The Multi-Talented Duck
1 exercise