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, toute autre classe peut l’étendre (sauf si vous la marquez final). Mais que faire si vous souhaitez autoriser l’héritage, mais pas de la part de n’importe qui ? Java 17 a introduit les classes scellées 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 à l’aide des 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 qui tente de l’étendre provoquera une erreur de compilation.

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

sealed class Vehicle permits Car, Truck { }

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

Les classes scellées sont particulièrement puissantes avec la correspondance de motifs 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 modes de paiement, les types de réponse ou les formes géométriques.

challenge icon

Défi

Facile

Construisons un système de notifications qui illustre les classes scellées en limitant les types de notifications pouvant exister dans votre application. Vous créerez une hiérarchie où seuls certains types de notifications sont autorisés, et où chaque type gère la livraison différemment.

Vous organiserez votre code sur quatre fichiers :

  • Notification.java : créez une classe abstraite scellée qui sert de base à toutes les notifications. Elle doit autoriser exactement trois sous-classes : EmailNotification, SMSNotification et PushNotification. Votre classe scellée doit posséder un champ protégé message (String), un constructeur pour l'initialiser, un getter pour le message, ainsi qu'une méthode abstraite deliver() qui renvoie 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) correspondant à l'adresse e-mail. Son constructeur doit recevoir le message et le destinataire, en appelant le constructeur parent avec super(). La méthode deliver() doit renvoyer : 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 reçoit le message et le numéro de téléphone. La méthode deliver() doit renvoyer : 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 reçoit le message et l'identifiant de l'appareil. La méthode deliver() doit renvoyer : Sending push to device [deviceId]: [message]
  • Main.java : assemblez votre système de notifications ! 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 notification de chaque type en utilisant le même message, mais leurs coordonnées respectives. Stockez les trois notifications dans un tableau de type Notification[] afin de démontrer le polymorphisme avec les classes scellées. Parcourez ensuite le tableau et affichez le résultat de l'appel à deliver() sur chaque notification.

Vous recevrez quatre entrées dans l'ordre suivant : 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 une 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
        
        // 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

Entraînez-vous par vous-même : Compilateur Java en ligne