Menu
Coddy logo textTech

Interface vs Classe Abstraite

Fait partie de la section Programmation Orientée Objet du Journey PHP de Coddy — leçon 30 sur 91.

Maintenant que vous avez appris à la fois les interfaces et les classes abstraites, clarifions quand utiliser chacune d'elles. Bien qu'elles puissent sembler similaires, elles servent des objectifs différents et possèdent des capacités distinctes.

Caractéristique Interface Classe abstraite
Méthodes Uniquement les signatures de méthode Méthodes abstraites et concrètes
Propriétés Uniquement des constantes Peut avoir des propriétés
Héritage multiple Une classe peut en implémenter plusieurs Une classe ne peut en étendre qu'une seule
Constructeur Non autorisé Peut avoir un constructeur

Utilisez une interface lorsque vous souhaitez définir un contrat que des classes non liées peuvent remplir. Par exemple, un Printer et un Logger peuvent tous deux implémenter une interface Writable, même s'ils ne partagent aucun ancêtre commun.

Utilisez une classe abstraite lorsque vous avez des classes apparentées qui partagent du code commun. Si vos classes Dog et Cat ont toutes deux besoin de la même implémentation de la méthode eat(), une classe abstraite Animal vous permet d'écrire ce code une seule fois.

Vous pouvez également combiner les deux approches. Une classe peut étendre une classe abstraite tout en implémentant plusieurs interfaces :

<?php
abstract class Animal {
    protected $name;
    
    public function eat() {
        return $this->name . " is eating";
    }
}

interface Swimmable {
    public function swim();
}

class Duck extends Animal implements Swimmable {
    public function __construct($name) {
        $this->name = $name;
    }
    
    public function swim() {
        return $this->name . " is swimming";
    }
}

Point clé : Choisissez des interfaces pour définir des capacités à travers des classes non liées. Choisissez des classes abstraites lorsque vous avez besoin de partager du code entre des classes liées.

challenge icon

Défi

Facile

Construisons un système de véhicules qui démontre quand utiliser une classe abstraite par rapport à une interface — et comment combiner les deux approches efficacement.

Vous allez créer un système où les véhicules partagent des propriétés communes via l'héritage, mais peuvent également acquérir des capacités supplémentaires via des interfaces. Cela reflète les décisions de conception du monde réel : une voiture « est un » véhicule (héritage), mais elle « a aussi la capacité » d'être ravitaillable en carburant (interface).

Organisez votre code sur quatre fichiers :

  • Refuelable.php — Définissez une interface Refuelable avec une signature de méthode unique : refuel($amount). Cette capacité peut s'appliquer à n'importe quelle classe nécessitant un ravitaillement, quelle que soit sa hiérarchie d'héritage.
  • Vehicle.php — Définissez une classe abstraite Vehicle qui fournit des fonctionnalités partagées pour tous les véhicules. Elle doit avoir une propriété protégée $brand et une propriété protégée $fuelLevel (commençant à 0). Le constructeur accepte le nom de la marque. Incluez une méthode concrète getBrand() qui retourne la marque, une méthode concrète getFuelLevel() qui retourne le niveau de carburant actuel, et une méthode abstraite drive() que les classes enfants doivent implémenter.
  • Car.php — Créez une classe Car qui étend Vehicle et implémente Refuelable. Incluez les deux fichiers requis en haut. Le constructeur accepte la marque et la transmet au constructeur parent. Implémentez drive() pour retourner "[brand] car is driving". Implémentez refuel($amount) pour ajouter le montant au niveau de carburant et retourner "[brand] refueled to [fuelLevel] liters".
  • main.php — Incluez le fichier Car. Vous recevrez deux entrées : un nom de marque et une quantité de carburant (convertissez en entier). Créez une Car avec la marque. Affichez le résultat de drive() sur la première ligne, puis affichez le résultat de refuel() avec la quantité de carburant sur la deuxième ligne.

Ce défi illustre la distinction clé : la classe abstraite Vehicle partage du code et établit une relation de type « est un », tandis que l'interface Refuelable ajoute une capacité qui pourrait s'appliquer à d'autres classes non liées (comme un générateur ou un bateau) sans exiger qu'elles soient des véhicules.

Aide-mémoire

Les interfaces et les classes abstraites servent des objectifs différents :

Caractéristique Interface Classe Abstraite
Méthodes Uniquement les signatures de méthodes Méthodes abstraites et concrètes
Propriétés Uniquement des constantes Peut avoir des propriétés
Héritage multiple Une classe peut en implémenter plusieurs Une classe ne peut en étendre qu'une seule
Constructeur Non autorisé Peut avoir un constructeur

Utilisez une interface pour définir un contrat pour des classes non liées. Utilisez une classe abstraite pour partager du code commun entre des classes liées.

Une classe peut étendre une classe abstraite tout en implémentant plusieurs interfaces :

<?php
abstract class Animal {
    protected $name;
    
    public function eat() {
        return $this->name . " is eating";
    }
}

interface Swimmable {
    public function swim();
}

class Duck extends Animal implements Swimmable {
    public function __construct($name) {
        $this->name = $name;
    }
    
    public function swim() {
        return $this->name . " is swimming";
    }
}

Essayez vous-même

<?php
require_once 'Car.php';

// Lire l'entrée
$brand = trim(fgets(STDIN));
$fuelAmount = intval(trim(fgets(STDIN)));

// TODO: Créer une voiture (Car) avec la marque

// TODO: Afficher le résultat de drive() sur la première ligne

// TODO: Afficher le résultat de refuel() avec la quantité de carburant sur la deuxième ligne
?>
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet