Patron État
Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy — leçon 74 sur 87.
Le State Pattern est un patron de conception comportemental qui permet à un objet de modifier son comportement lorsque son état interne change. L'objet semble changer de classe, mais en réalité, il délègue le comportement à différents objets d'état. Pensez à un distributeur automatique : sa réponse à l'appui sur un bouton dépend de s'il est au repos, si de l'argent a été inséré ou s'il est en train de distribuer un produit.
Au lieu d'utiliser des instructions conditionnelles complexes pour gérer différents états, vous encapsulez chaque état dans sa propre classe. Le patron implique un Context qui maintient une référence vers l'état actuel, et des classes State qui définissent le comportement pour chaque état :
interface State {
void handle(Context context);
}
class Context {
private State state;
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}Chaque état concret implémente le comportement et peut déclencher des transitions vers d'autres états :
class IdleState implements State {
public void handle(Context context) {
System.out.println("Idle: Insert coin to start");
context.setState(new ActiveState());
}
}
class ActiveState implements State {
public void handle(Context context) {
System.out.println("Active: Processing...");
context.setState(new IdleState());
}
}Le contexte délègue les requêtes à son état actuel, et le comportement change automatiquement à mesure que l'état change :
Context context = new Context();
context.setState(new IdleState());
context.request(); // Inactif : Insérez une pièce pour démarrer
context.request(); // Actif : Traitement en cours...Le State Pattern est idéal lorsque le comportement d'un objet dépend fortement de son état et doit changer à l'exécution. Il élimine les gros blocs conditionnels et rend l'ajout de nouveaux états simple — il suffit de créer une nouvelle classe implémentant l'interface State.
Défi
FacileConstruisons un système de flux de travail de documents en utilisant le State Pattern ! Vous allez créer un système qui modélise la façon dont un document passe par différentes étapes — Draft, Review et Published — chaque état déterminant quelles actions sont disponibles et comment le document se comporte lorsque vous essayez de le modifier ou de l'approuver.
Vous organiserez votre code sur quatre fichiers :
DocumentState.java: Définissez l'interfaceDocumentStateque tous les états implémenteront. Elle doit déclarer deux méthodes :edit(Document doc)pour tenter de modifier le document, etapprove(Document doc)pour tenter d'approuver/faire passer le document à l'étape suivante.States.java: Créez trois classes d'états concrètes qui implémententDocumentState:DraftState- Lorsqueeditest appelé, affichezEditing draft.... Lorsqueapproveest appelé, affichezDraft approved. Moving to review.et faites passer le document àReviewState.ReviewState- Lorsqueeditest appelé, affichezCannot edit during review.(pas de changement d'état). Lorsqueapproveest appelé, affichezReview complete. Publishing document.et passez àPublishedState.PublishedState- Lorsqueeditest appelé, affichezCannot edit published document.. Lorsqueapproveest appelé, affichezDocument already published.. Aucune des deux actions ne change l'état.Document.java: Créez la classe de contexte qui maintient l'état actuel. VotreDocumentdoit avoir :Un champ privé contenant le
DocumentStateactuel, initialisé àDraftStatedans le constructeur.Une méthode
setState(DocumentState state)qui change l'état actuel.Une méthode
edit()qui délègue à la méthodeeditde l'état actuel.Une méthode
approve()qui délègue à la méthodeapprovede l'état actuel.Une méthode
getStatus()qui retourne le nom simple de la classe de l'état actuel (utilisezgetClass().getSimpleName()).Main.java: Démontrez votre système d'états ! Vous recevrez une entrée : une séquence d'actions sous forme de chaîne de caractères séparée par des virgules où chaque action est soiteditsoitapprove(par exemple :edit,approve,edit,approve).Créez un
Documentet affichez son statut initial au formatStatus: [state]. Ensuite, traitez chaque action dans l'ordre, en appelant la méthode appropriée sur le document. Après chaque action, affichez le statut actuel.
Vous recevrez une entrée : une chaîne d'actions séparée par des virgules.
Par exemple, avec l'entrée edit,approve,approve, votre sortie serait :
Status: DraftState
Editing draft...
Status: DraftState
Draft approved. Moving to review.
Status: ReviewState
Review complete. Publishing document.
Status: PublishedStateRemarquez comment le même appel à approve() produit des résultats différents selon l'état actuel du document — c'est l'essence même du State Pattern ! Le document n'utilise pas de conditions pour vérifier son état ; au lieu de cela, il délègue le comportement à l'objet d'état actuel, qui gère l'action de manière appropriée et déclenche les transitions si nécessaire.
Aide-mémoire
Le State Pattern est un patron de conception comportemental qui permet à un objet de changer son comportement lorsque son état interne change en déléguant le comportement à différents objets d'état au lieu d'utiliser des instructions conditionnelles complexes.
Le patron se compose d'un Context qui maintient une référence à l'état actuel, et de classes State qui définissent le comportement pour chaque état :
interface State {
void handle(Context context);
}
class Context {
private State state;
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}Chaque état concret implémente le comportement et peut déclencher des transitions vers d'autres états :
class IdleState implements State {
public void handle(Context context) {
System.out.println("Idle: Insert coin to start");
context.setState(new ActiveState());
}
}
class ActiveState implements State {
public void handle(Context context) {
System.out.println("Active: Processing...");
context.setState(new IdleState());
}
}Le contexte délègue les requêtes à son état actuel, et le comportement change automatiquement à mesure que l'état change :
Context context = new Context();
context.setState(new IdleState());
context.request(); // Idle: Insert coin to start
context.request(); // Active: Processing...Le State Pattern est idéal lorsque le comportement d'un objet dépend fortement de son état et doit changer au moment de l'exécution. Il élimine les grands blocs conditionnels et rend l'ajout de nouveaux états simple.
Essayez vous-même
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: Créer un nouveau Document
// TODO: Afficher le statut initial au format "Status: [state]"
// TODO: Diviser l'entrée par la virgule pour obtenir les actions individuelles
// TODO: Parcourir chaque action
// - Si l'action est "edit", appeler edit() sur document
// - Si l'action est "approve", appeler approve() sur document
// - Après chaque action, afficher le statut actuel
}
}
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 externesIntroduction à la POOClasses vs ObjetsLe mot-clé thisMéthodesChamps (Attributs)Méthode constructeurSurcharge de constructeurRécapitulatif - Calculatrice simple4Héritage
Héritage de base (extends)Le mot-clé superRedéfinition de méthode (@Override)Chaînage de constructeursLa classe ObjectHéritage simple et multiniveauPourquoi pas d'héritage multiple de classesRécapitulatif - Hiérarchie des employés7Méthodes spéciales et classe Object
Méthode toString()equals() et hashCode()Méthode clone()compareTo() et ComparableInterface ComparatorRécapitulatif - Tri personnalisé2Modificateurs d'accès et Encapsulation
Aperçu des niveaux d'accèsMéthodes Getter et SetterMasquage d'informationsLe mot-clé finalRécapitulatif - Gestionnaire de compte bancaire5Polymorphisme
Bases de la surcharge de méthodesRedéfinition de méthodes (Run-Time)Upcasting et DowncastingL'opérateur instanceofClasses et méthodes abstraitesRécapitulatif - Calculateur de formes8Concepts avancés de la POO
Composition vs HéritageAgrégation vs CompositionClasses internes, imbriquées et anonymesEnums et méthodes d'EnumRecords (Java 16+)Classes scellées (Java 17+)11Patrons de conception, partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron MonteurPatron ObservateurPatron Stratégie3Propriétés de classe et membres statiques
Variables d'instance vs variables statiquesMéthodes statiquesBlocs statiquesConstantes (static final)Récapitulatif - Compteur et utilitaire6Interfaces et Classes Abstraites
Introduction aux InterfacesImplémentation d'InterfacesImplémentation d'Interfaces MultiplesDefault et Static dans les InterfacesClasses Abstraites vs InterfacesInterfaces FonctionnellesRécapitulatif - Système de Paiement9La généricité
Introduction à la généricitéClasses génériquesMéthodes génériquesParamètres de type bornésWildcards (?, extends, super)Récapitulatif - Conteneur générique12Patrons de conception, partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositePatron Itérateur