Les Interfaces

Un contrat que les classes s'engagent a respecter. La cle du code flexible et extensible.

Respecter le contrat

Une interface est une prise : pour s'y brancher, une classe doit implémenter toutes ses méthodes. Branche une classe et regarde la prise s'emboîter.

«interface» Volant decoller() atterrir() class ... decoller() ? atterrir() ?

Choisis une classe à brancher sur l'interface Volant.

L'analogie du port USB

Une interface, c'est comme un port USB : peu importe ce que tu branches (souris, clavier, cle USB), ca marche parce que tout le monde respecte le meme standard.

Le port = l'interface (le contrat)
🖱️
⌨️
💾
🎮
Les peripheriques = les classes qui implementent l'interface

💡 L'idee cle : Le port ne sait pas CE QUI est branche, il sait juste que ca respecte le contrat USB. C'est pareil en code : une fonction peut accepter n'importe quel objet qui implemente une interface.

C'est quoi une interface ?

Interface = Contrat

L'interface definit les methodes qu'une classe doit avoir, sans dire comment les implementer.

parler() → string
seDeplacer() → void

"Je promets d'avoir ces methodes, mais je choisis comment"

🐕 Chien implemente Animal
parler() → "Wouf!"
seDeplacer() → courrir()
🐟 Poisson implemente Animal
parler() → "Blub!"
seDeplacer() → nager()

Syntaxe selon le langage

Chaque langage a sa facon de definir des interfaces (ou equivalents)

Definir l'interface

public interface Drawable {
    // Methodes sans corps (juste la signature)
    void draw();
    String getColor();
}

// Une classe peut implementer PLUSIEURS interfaces
public interface Clickable {
    void onClick();
}
interface Drawable {
    draw(): void;
    getColor(): string;
}

// TypeScript permet aussi des proprietes
interface Clickable {
    isEnabled: boolean;
    onClick(): void;
}
// Go : interface implicite (pas de "implements")
type Drawable interface {
    Draw()
    GetColor() string
}

type Clickable interface {
    OnClick()
}
from abc import ABC, abstractmethod

# Python : classes abstraites (ABC)
class Drawable(ABC):
    @abstractmethod
    def draw(self):
        pass

    @abstractmethod
    def get_color(self) -> str:
        pass

# Alternative : Protocol (Python 3.8+)
from typing import Protocol

class Clickable(Protocol):
    def on_click(self) -> None: ...

Implementer l'interface

public class Circle implements Drawable, Clickable {
    private String color = "rouge";

    @Override  // Obligatoire : implementer TOUTES les methodes
    public void draw() {
        System.out.println("Dessine un cercle " + color);
    }

    @Override
    public String getColor() {
        return this.color;
    }

    @Override
    public void onClick() {
        System.out.println("Cercle clique!");
    }
}
class Circle implements Drawable, Clickable {
    isEnabled = true;
    private color = "rouge";

    draw(): void {
        console.log(`Dessine un cercle ${this.color}`);
    }

    getColor(): string {
        return this.color;
    }

    onClick(): void {
        console.log("Cercle clique!");
    }
}
// Go : implementation IMPLICITE
// Si une struct a les bonnes methodes, elle implemente l'interface

type Circle struct {
    color string
}

func (c Circle) Draw() {
    fmt.Println("Dessine un cercle", c.color)
}

func (c Circle) GetColor() string {
    return c.color
}

func (c Circle) OnClick() {
    fmt.Println("Cercle clique!")
}
// Circle implemente automatiquement Drawable et Clickable!
class Circle(Drawable):  # Herite de l'ABC
    def __init__(self):
        self.color = "rouge"

    def draw(self):  # DOIT implementer
        print(f"Dessine un cercle {self.color}")

    def get_color(self) -> str:
        return self.color

# Avec Protocol (duck typing)
class Square:  # Pas besoin d'heriter!
    def on_click(self):
        print("Carre clique!")
# Square est compatible avec Clickable grace au duck typing

Pourquoi utiliser des interfaces ?

🔌

Flexibilite

Changer l'implementation sans toucher au reste du code. Exemple : passer de MySQL a PostgreSQL.

🧪

Testabilite

Creer des "mocks" pour les tests. Simuler une BDD, une API, un service externe.

🧩

Heritage multiple

Une classe peut implementer plusieurs interfaces (impossible avec l'heritage simple en Java/C#).

📋

Documentation

L'interface documente ce qu'un objet peut faire. Contrat clair entre les devs.

Exemple : Systeme de paiement

Imagine un site e-commerce. Tu veux accepter plusieurs moyens de paiement sans changer le code du checkout a chaque nouveau moyen.

// L'interface commune
interface PaymentMethod {
    pay(amount: number): boolean;
    getName(): string;
}
// Le checkout utilise l'interface
function checkout(method: PaymentMethod, amount: number) {
    console.log(`Paiement via ${method.getName()}...`);

    if (method.pay(amount)) {
        console.log("Paiement reussi!");
    }
}

// Peu importe l'implementation :
checkout(???, 99.99);

💡 L'avantage : Pour ajouter Stripe, Klarna ou n'importe quel autre moyen de paiement, tu crees juste une nouvelle classe qui implemente PaymentMethod. Le code du checkout ne change pas !

Interface vs Classe Abstraite

Critere Interface Classe Abstraite
Code implementation ❌ Non (que signatures) ✅ Oui (methodes concretes possibles)
Heritage multiple ✅ Oui (implements X, Y, Z) ❌ Non (extends une seule)
Attributs ❌ Non (constantes seulement) ✅ Oui
Constructeur ❌ Non ✅ Oui
Utilisation Definir un contrat Partager du code commun

🎯 Regle generale : Utilise une interface pour definir "ce que fait" un objet. Utilise une classe abstraite pour partager "comment il le fait".

Mode Survie : Interfaces

Une erreur = Game Over ! 10 questions aléatoires.

Continuer vers Collections (ArrayList, HashMap)
⬇️
Avancé