Menu
Coddy logo textTech

Classes scellées (Java 17+)

Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy — leçon 52 sur 87.

En Java traditionnel, lorsque vous créez une classe, n'importe quelle autre classe peut l'étendre (à moins que vous ne la marquiez comme final). Mais que se passe-t-il si vous voulez autoriser l'héritage, mais pas de la part de n'importe qui ? Java 17 a introduit les sealed classes pour vous donner un contrôle précis sur les classes qui peuvent étendre la vôtre.

Une classe scellée déclare explicitement ses sous-classes autorisées en utilisant les mots-clés sealed et permits :

sealed abstract class Shape permits Circle, Rectangle, Triangle {
    abstract double area();
}

final class Circle extends Shape {
    double radius;
    double area() { return Math.PI * radius * radius; }
}

final class Rectangle extends Shape {
    double width, height;
    double area() { return width * height; }
}

final class Triangle extends Shape {
    double base, height;
    double area() { return 0.5 * base * height; }
}

Seuls Circle, Rectangle, et Triangle peuvent étendre Shape. Toute autre classe tentant de l'étendre provoquera une erreur de compilation.

Chaque sous-classe autorisée doit utiliser l'un des trois modificateurs : final (aucune extension supplémentaire), sealed (continue la chaîne de restriction) ou non-sealed (ouvre à une extension sans restriction) :

sealed class Vehicle permits Car, Truck { }

final class Car extends Vehicle { }           // Ne peut pas être étendue
non-sealed class Truck extends Vehicle { }    // N'importe qui peut étendre Truck

Les classes scellées sont particulièrement puissantes avec le filtrage par motif (pattern matching) dans les expressions switch, car le compilateur connaît tous les sous-types possibles et peut vérifier l'exhaustivité. Elles sont idéales pour modéliser un ensemble fixe de types dans un domaine, comme les méthodes de paiement, les types de réponse ou les formes géométriques.

challenge icon

Défi

Facile

Construisons un système de notification qui illustre les classes scellées (sealed classes) en restreignant les types de notifications pouvant exister dans votre application. Vous allez créer une hiérarchie où seuls des types de notification spécifiques sont autorisés, et chaque type gère la distribution différemment.

Vous organiserez votre code sur quatre fichiers :

  • Notification.java : Créez une classe abstraite scellée (sealed abstract class) qui sert de base à toutes les notifications. Elle doit autoriser exactement trois sous-classes : EmailNotification, SMSNotification, et PushNotification. Votre classe scellée a besoin d'un champ protégé message (String), d'un constructeur pour l'initialiser, d'un getter pour le message, et d'une méthode abstraite deliver() qui retourne une String décrivant comment la notification est envoyée.
  • EmailNotification.java : Créez une classe final qui étend Notification. Une EmailNotification possède un champ privé supplémentaire recipient (String) pour l'adresse e-mail. Son constructeur doit prendre à la fois le message et le destinataire, en appelant le constructeur parent avec super(). La méthode deliver() doit retourner : "Sending email to " + recipient + ": " + message
  • SMSNotification.java : Créez une classe non-sealed qui étend Notification—cela permet à d'autres classes de l'étendre si nécessaire à l'avenir. Une SMSNotification possède un champ privé supplémentaire phoneNumber (String). Son constructeur prend le message et le numéro de téléphone. La méthode deliver() doit retourner : "Sending SMS to " + phoneNumber + ": " + message
  • PushNotification.java : Créez une classe final qui étend Notification. Une PushNotification possède un champ privé supplémentaire deviceId (String). Son constructeur prend le message et l'identifiant de l'appareil. La méthode deliver() doit retourner : "Sending push to device " + deviceId + ": " + message
  • Main.java : Rassemblez votre système de notification ! Vous recevrez quatre entrées : un message (String), une adresse e-mail (String), un numéro de téléphone (String), et un identifiant d'appareil (String).

    Créez une instance de chaque type de notification en utilisant le même message mais leurs informations de contact respectives. Stockez les trois dans un tableau de type Notification[] pour démontrer le polymorphisme avec les classes scellées. Ensuite, parcourez le tableau et affichez le résultat de l'appel à deliver() sur chaque notification.

Vous recevrez quatre entrées dans l'ordre : message, adresse e-mail, numéro de téléphone et identifiant d'appareil.

Remarquez comment la classe scellée restreint la hiérarchie—seules les trois classes autorisées peuvent étendre Notification. Chaque sous-classe doit se déclarer comme final, sealed, ou non-sealed. Cela vous donne un contrôle total sur votre hiérarchie de types tout en permettant le polymorphisme !

Essayez vous-même

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Lire les quatre entrées
        String message = scanner.nextLine();
        String email = scanner.nextLine();
        String phoneNumber = scanner.nextLine();
        String deviceId = scanner.nextLine();
        
        // TODO: Créer un exemplaire de chaque type de notification en utilisant le même message
        // - EmailNotification avec message et email
        // - SMSNotification avec message et phoneNumber
        // - PushNotification avec message et deviceId
        
        // TODO: Stocker les trois notifications dans un tableau Notification[]
        // Ceci démontre le polymorphisme avec les classes scellées (sealed classes)
        
        // TODO: Parcourir le tableau et afficher le résultat de deliver()
        // pour chaque notification
        
    }
}
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