Interface vs Classe Abstraite
Fait partie de la section Programmation Orientée Objet du Journey C# de Coddy. Leçon 26 sur 70.
Les interfaces et les classes abstraites vous permettent toutes deux de définir des contrats que les autres classes doivent respecter, mais elles ont des objectifs différents et des capacités distinctes.
Une interface définit ce qu’une classe doit faire, sans aucune implémentation. C’est un contrat pur :
public interface IFlyable
{
void Fly();
}
public class Bird : IFlyable
{
public void Fly()
{
Console.WriteLine("Flapping wings");
}
}Une classe abstraite peut fournir à la fois un contrat et une implémentation partagée. Il s’agit d’un plan partiel :
public abstract class Vehicle
{
public string Brand { get; set; }
public void StartEngine()
{
Console.WriteLine("Engine started");
}
public abstract void Drive(); // Doit être implémenté
}
public class Car : Vehicle
{
public override void Drive()
{
Console.WriteLine("Driving on roads");
}
}Les principales différences tiennent aux règles d’héritage et à la finalité.
Une classe peut implémenter plusieurs interfaces, mais n’hériter que d’une seule classe abstraite.
Utilisez une interface lorsque des classes sans lien doivent partager un comportement (comme IFlyable pour les oiseaux et les avions). Utilisez une classe abstraite lorsque des classes apparentées partagent du code et un état communs (comme des véhicules qui partagent un mécanisme de démarrage du moteur).
Les classes abstraites peuvent avoir des constructeurs, des champs et des modificateurs d’accès sur leurs membres. Traditionnellement, les interfaces ne le pouvaient pas, bien que C# moderne autorise les implémentations par défaut.
En cas de doute, privilégiez les interfaces pour plus de flexibilité : vous pourrez toujours ajouter une classe abstraite ultérieurement si une implémentation partagée devient nécessaire.
Défi
FacileConstruisons un système de lecteur multimédia qui montre quand utiliser des interfaces plutôt que des classes abstraites. Vous allez créer une conception où des appareils sans lien partagent le comportement de lecture grâce à une interface, tandis que des types de médias associés partagent une implémentation commune grâce à une classe abstraite.
Vous organiserez votre code sur quatre fichiers :
IPlayable.cs: définissez une interface appeléeIPlayabledans l’espace de nomsMedia. Cette interface représente le contrat pour tout ce qui peut lire des médias — qu’il s’agisse d’un téléphone, d’un téléviseur ou d’un lecteur de musique dédié. Elle doit déclarer une seule méthodePlay()qui retourne une chaîne de caractères.MediaFile.cs: définissez une classe abstraite appeléeMediaFiledans l’espace de nomsMedia. Elle représente la base commune de tous les fichiers multimédias. Elle doit avoir une propriétéTitle(string) et une propriétéDuration(int, représentant des secondes). Incluez un constructeur qui définit ces deux valeurs. Ajoutez une méthode concrète appeléeGetInfo()qui retourne"{Title} ({Duration}s)". Déclarez également une méthode abstraiteGetType()qui retourne une chaîne de caractères — chaque type de média définira de quel type de fichier il s’agit.AudioFile.cs: définissez une classeAudioFiledans l’espace de nomsMediaqui hérite deMediaFileet implémenteIPlayable. Ajoutez une propriétéArtist(string). Le constructeur doit accepter le titre, la durée et l’artiste. RedéfinissezGetType()pour retourner"Audio". ImplémentezPlay()pour retourner"Playing audio: {Title} by {Artist}".Program.cs: dans votre fichier principal, créez unAudioFileà l’aide des valeurs saisies. Montrez les deux aspects de la classe : appelezGetInfo()etGetType()(héritées de la classe abstraite), puis appelezPlay()(provenant de l’interface). Stockez le fichier audio dans une variableIPlayableet appelez à nouveauPlay()pour montrer le polymorphisme d’interface.
Vous recevrez trois entrées :
- Titre de la chanson
- Durée en secondes
- Nom de l’artiste
Affichez la sortie dans ce format :
Info: {GetInfo() result}
Type: {GetType() result}
Direct: {Play() result}
Via Interface: {Play() result from IPlayable variable}Par exemple, si les entrées sont Bohemian Rhapsody, 354 et Queen, la sortie doit être :
Info: Bohemian Rhapsody (354s)
Type: Audio
Direct: Playing audio: Bohemian Rhapsody by Queen
Via Interface: Playing audio: Bohemian Rhapsody by QueenRemarquez comment AudioFile tire parti des deux approches : il hérite de l’implémentation partagée (GetInfo()) de la classe abstraite tout en respectant le contrat IPlayable. La classe abstraite permet de réutiliser le code pour les types de médias associés, tandis que l’interface permet à toute classe sans lien d’être « lisible » sans partager de hiérarchie d’héritage.
Essayez vous-même
using System;
using Media;
class Program
{
public static void Main(string[] args)
{
// Lire les valeurs d'entrée
string title = Console.ReadLine();
int duration = Convert.ToInt32(Console.ReadLine());
string artist = Console.ReadLine();
// TODO: Créer un AudioFile en utilisant les valeurs d'entrée
// TODO: Afficher Info: suivi du résultat de GetInfo()
// TODO: Afficher Type: suivi du résultat de GetType()
// TODO: Afficher Direct: suivi du résultat de Play()
// TODO: Stocker le fichier audio dans une variable IPlayable
// TODO: Afficher Via Interface: suivi du résultat de Play() depuis la variable IPlayable
}
}
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
1Fondamentaux de la POO
Fichiers externesEspaces de noms et directivesIntro aux classes et objetsLe mot-clé 'this'Méthodes et paramètresChamps vs PropriétésConstructeursInitialiseurs d'objetsRécapitulatif - Calculatrice simple4Héritage
Syntaxe de base de l'héritage (:)Le mot-clé 'base'Mots-clés Virtual & OverrideClasses scelléesLa classe de base 'object'Récapitulatif - Hiérarchie des employés7Fonctionnalités avancées
Surcharge d'opérateursIndexeurs (this[])Redéfinition de ToString()Méthodes d'extensionRécapitulatif - Liste personnalisée10Patrons de conception - Partie 1
Introduction aux patrons de conceptionSingleton Thread-SafePatron FabriquePatron Observateur (Événements)Patron Stratégie2Propriétés et membres statiques
Propriétés auto-implémentéesPropriétés en lecture/écriture seuleChamps et méthodes statiquesClasses statiquesMembres à corps d'expression5Polymorphisme & Interfaces
Polymorphisme : Compilation vs ExécutionInterface vs Classe AbstraiteInterfaces MultiplesInterfaces ExplicitesUpcasting & DowncastingRécapitulatif - Calculateur de Formes8Concepts avancés de la POO
Composition plutôt qu'héritageGénériques (Classes et Méthodes)Délégués et ÉvénementsAttributs et RéflexionIDisposable et l'instruction usingBases de l'Injection de Dépendances11Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode TemplatePatron ÉtatPatron Composite3Architecture des classes
Données d'instance vs statiquesMots-clés 'readonly' & 'const'Champs de supportRécapitulatif - Gestionnaire de compte bancaire6Encapsulation
Modificateurs d'accèsPropriétés pour l'encapsulationImplémentation du masquage de donnéesPatterns d'immuabilitéRécapitulatif - Dossiers d'étudiants12Projet : Système de gestion de bibliothèque
Structure du projetModèles Livre et UtilisateurLogique du système d'empruntLINQ pour la rechercheInterface Console / Interface d'administrationTests unitaires (NUnit/xUnit)Entraînez-vous par vous-même : Compilateur C# en ligne