Les classes scellées Java ont été introduites dans Java 15 comme moyen de restreindre la hiérarchie d’héritage d’une classe ou d’une interface.
Une classe ou une interface scellée restreint l’ensemble des classes qui peuvent les implémenter ou les étendre, ce qui peut aider à prévenir les bogues et rendre le code plus maintenable.
Supposons que vous construisiez une application de commerce électronique prenant en charge différents modes de paiement, tels que les cartes de crédit, PayPal et Bitcoin. Vous pouvez définir une classe scellée appelée PaymentMethod
qui autorise différentes sous-classes pour chaque mode de paiement :
public sealed class PaymentMethod permits CreditCard, PayPal, Bitcoin {
// Class members
}
Dans cet exemple, PaymentMethod
est une classe scellée qui permet CreditCard
, PayPal
et Bitcoin
pour le prolonger. Une classe scellée peut permettre à n’importe quel nombre de classes de l’étendre en les spécifiant dans une liste séparée par des virgules après le mot clé permit.
Il existe de nombreux autres cas d’utilisation où la classe scellée peut être utilisée pour nous faciliter la vie.
Alors allons-y pour une plongée profonde!
Création d’une hiérarchie de type fermé
Les classes scellées peuvent créer une hiérarchie de type fermé ; un ensemble limité de classes qui ne peuvent pas être étendues ou implémentées en dehors d’un package particulier.
Cela garantit que seul un ensemble spécifié de classes peut être utilisé et empêche les extensions ou les implémentations indésirables.
package ca.bazlur
public sealed class Animal permits Cat, Dog {
// Class definition
}
public final class Cat extends Animal {
// Class definition
}
public final class Dog extends Animal {
// Class definition
}
Dans cet exemple, Animal
est une classe scellée qui permet uniquement Cat
et Dog
pour le prolonger.
Toute autre tentative d’extension Animal
entraînera une erreur de compilation.
Création d’un ensemble limité d’implémentations
Les classes scellées peuvent également créer un ensemble limité d’implémentations pour une interface spécifique ou une classe abstraite. Cela garantit que les propriétaires de l’interface ou de la classe abstraite peuvent contrôler et modifier l’ensemble des implémentations.
public sealed interface Shape permits Circle, Square {
double getArea();
}
public final class Circle implements Shape {
// Class definition
}
public final class Square implements Shape {
// Class definition
}
Dans cet exemple, Shape
est une interface scellée qui permet uniquement Circle
et Square
pour le mettre en œuvre.
Cela garantit que toute autre implémentation de Shape
ne peut pas être créé.
Amélioration de la correspondance de modèles dans les instructions switch
Les classes scellées peuvent également être utilisées pour améliorer la correspondance de modèles dans switch
déclarations.
En limitant l’ensemble de sous-types pouvant étendre une classe scellée, les développeurs peuvent utiliser la correspondance de modèles avec des vérifications exhaustives, garantissant que tous les sous-types possibles sont couverts.
public sealed abstract class PaymentMethod permits CreditCard, DebitCard, PayPal {
// Class definition
}
public class PaymentProcessor {
public void processPayment(PaymentMethod paymentMethod, double amount) {
switch (paymentMethod) {
case CreditCard cc -> {
// Process credit card payment
}
case DebitCard dc -> {
// Process debit card payment
}
case PayPal pp -> {
// Process PayPal payment
}
}
}
}
Dans cet exemple, PaymentMethod
est une classe scellée qui permet CreditCard
, DebitCard
et PayPal
pour le prolonger.
Le processPayment
méthode dans la PaymentProcessor
classe utilise un switch
relevé avec correspondance de modèle pour traiter différents modes de paiement.
L’utilisation d’une classe scellée garantit que tous les sous-types possibles sont couverts dans la switch
déclaration, ce qui la rend moins sujette aux erreurs.
Implémentation d’une machine d’état
Les classes scellées peuvent être utilisées pour implémenter une machine à états, un modèle de calcul qui définit le comportement d’un système en réponse à une série d’entrées. Dans une machine à états, chaque état est représenté par une classe scellée et les transitions entre états sont modélisées par des méthodes qui renvoient un nouvel état.
public sealed class State permits IdleState, ActiveState, ErrorState {
public State transition(Input input) {
// Transition logic
}
}
public final class IdleState extends State {
// Class definition
}
public final class ActiveState extends State {
// Class definition
}
public final class ErrorState extends State {
// Class definition
}
Dans cet exemple, State
est une classe scellée qui permet l’extension de IdleState
, ActiveState
et ErrorState
.
Le transition
La méthode est responsable de la transition entre les états en fonction de l’entrée fournie.
L’utilisation de classes scellées garantit que la machine d’état est bien définie et ne peut être étendue qu’avec un ensemble limité de classes.
Création d’un ensemble limité d’exceptions
Les classes scellées peuvent également créer un ensemble limité d’exceptions pouvant être levées par une méthode. Cela peut aider à appliquer un ensemble cohérent de conditions d’erreur et empêcher la création de types d’exception arbitraires.
public sealed class DatabaseException extends Exception permits ConnectionException, QueryException {
// Class definition
}
public final class ConnectionException extends DatabaseException {
// Class definition
}
public final class QueryException extends DatabaseException {
// Class definition
}
Dans cet exemple, DatabaseException
est une classe scellée qui permet ConnectionException
et QueryException
pour le prolonger.
Cela garantit que toute exception levée par une méthode liée à une opération de base de données est un type bien défini et peut être gérée de manière cohérente.
Contrôler l’accès aux constructeurs
Les classes scellées peuvent également contrôler l’accès aux constructeurs, ce qui peut aider à appliquer un ensemble spécifique d’invariants pour la classe.
public sealed class Person {
private final String name;
private final int age;
private Person(String name, int age) {
this.name = name;
this.age = age;
}
public static final class Child extends Person {
public Child(String name, int age) {
super(name, age);
if (age >= 18) {
throw new IllegalArgumentException("Children must be under 18 years old.");
}
}
}
public static final class Adult extends Person {
public Adult(String name, int age) {
super(name, age);
if (age < 18) {
throw new IllegalArgumentException("Adults must be 18 years old or older.");
}
}
}
}
Dans cet exemple, un Person
est une classe scellée avec deux sous-classes : Child
et Adult
.
Les constructeurs de Child
et Adult
sont marqués comme public
mais le constructeur de Person
est marqué comme private
assurant tout Person
les instances sont créées via ses sous-classes.
Cela permet au Person
pour appliquer l’invariant selon lequel les enfants doivent avoir moins de 18 ans et les adultes doivent avoir 18 ans ou plus.
Amélioration de la sécurité du code
Les classes scellées peuvent également améliorer la sécurité du code en garantissant que seul le code de confiance peut les étendre ou les implémenter. Cela peut aider à empêcher l’accès non autorisé aux parties sensibles de la base de code.
public sealed class SecureCode permits TrustedCode {
// Class definition
}
// Trusted code
public final class TrustedCode extends SecureCode {
// Class definition
}
// Untrusted code
public final class UntrustedCode extends SecureCode {
// Class definition
}
Dans cet exemple, SecureCode
est une classe scellée qui permet uniquement TrustedCode
pour le prolonger.
Cela garantit que seul le code de confiance peut accéder aux parties sensibles de la base de code.
Activation du polymorphisme avec correspondance de modèle exhaustive
Les classes scellées peuvent également être utilisées pour activer le polymorphisme avec une correspondance de modèle exhaustive.
En utilisant des classes scellées, les développeurs peuvent s’assurer que tous les sous-types possibles sont couverts dans une instruction de correspondance de modèle, permettant un code plus sûr et plus efficace.
public sealed class Shape permits Circle, Square {
// Class definition
}
public final class Circle extends Shape {
// Class definition
}
public final class Square extends Shape {
// Class definition
}
public void drawShape(Shape shape) {
switch (shape) {
case Circle c -> c.drawCircle();
case Square s -> s.drawSquare();
}
}
Dans cet exemple, Shape
est une classe scellée qui permet Circle
et Square
pour le prolonger.
Le drawShape
utilise la correspondance de motifs pour dessiner la forme, en veillant à ce que tous les sous-types possibles de Shape
sont couverts dans le switch
déclaration.
Amélioration de la lisibilité du code
Les classes scellées peuvent également être utilisées pour améliorer la lisibilité du code en définissant clairement l’ensemble des sous-types possibles.
En limitant l’ensemble des sous-types possibles, les développeurs peuvent plus facilement raisonner sur le code et comprendre son comportement.
public sealed class Fruit permits Apple, Banana, Orange {
// Class definition
}
public final class Apple extends Fruit {
// Class definition
}
public final class Banana extends Fruit {
// Class definition
}
public final class Orange extends Fruit {
// Class definition
}
Dans cet exemple, Fruit
est une classe scellée qui permet Apple
, Banana
et Orange
pour le prolonger.
Cela définit clairement l’ensemble des fruits possibles et améliore la lisibilité du code en rendant le code plus facile à comprendre.
Application des contrats d’API
Les classes scellées peuvent également être utilisées pour appliquer les contrats d’API, qui sont l’ensemble des attentes que les consommateurs d’une API ont concernant son comportement.
En utilisant des classes scellées, les fournisseurs d’API peuvent s’assurer que l’ensemble de sous-types possibles est bien défini et documenté, améliorant ainsi la convivialité et la maintenabilité de l’API.
public sealed class Vehicle permits Car, Truck, Motorcycle {
// Class definition
}
public final class Car extends Vehicle {
// Class...