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.
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.
💡 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.
"Je promets d'avoir ces methodes, mais je choisis comment"
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.
interface PaymentMethod { pay(amount: number): boolean; getName(): string; }
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.