Menu
Coddy logo textTech

Modèle État

Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy. Leçon 95 sur 107.

Le pattern State permet à un objet de modifier son comportement lorsque son état interne change, donnant l’impression que l’objet a changé de classe. Alors que Template Method contrôle les étapes de l’algorithme, State encapsule le comportement propre à chaque état dans des objets distincts et délègue à l’état actuel.

En Go, nous définissons une interface d’état et créons des états concrets qui implémentent différents comportements :

type State interface {
    Handle(d *Document) string
}

type Document struct {
    state State
}

func (d *Document) SetState(s State) {
    d.state = s
}

func (d *Document) Publish() string {
    return d.state.Handle(d)
}

Chaque état détermine ce qui se passe et quel état vient ensuite :

type DraftState struct{}

func (s DraftState) Handle(d *Document) string {
    d.SetState(ModerationState{})
    return "Draft submitted for moderation"
}

type ModerationState struct{}

func (s ModerationState) Handle(d *Document) string {
    d.SetState(PublishedState{})
    return "Moderation approved, now published"
}

type PublishedState struct{}

func (s PublishedState) Handle(d *Document) string {
    return "Already published"
}

Le même appel de méthode produit des résultats différents selon l’état actuel :

doc := &Document{state: DraftState{}}

fmt.Println(doc.Publish())  // Brouillon soumis pour modération
fmt.Println(doc.Publish())  // Modération approuvée, maintenant publié
fmt.Println(doc.Publish())  // Déjà publié

State est idéal pour les objets ayant des modes de fonctionnement distincts, tels que les flux de traitement des commandes, les composants d’interface utilisateur ou les gestionnaires de connexions dont le comportement dépend entièrement de l’état actuel.

challenge icon

Défi

Facile

Construisons un système de gestion des tickets d'assistance en utilisant le pattern State ! Vous allez créer un ticket d'assistance qui passe par différentes étapes, de son ouverture à sa résolution, en passant par sa prise en charge, chaque état déterminant les actions possibles et ce qui se passe ensuite.

Vous allez organiser votre code sur trois fichiers :

  • state.go : définissez votre interface d'état ainsi que les états concrets qui représentent chaque étape du cycle de vie d'un ticket.

    Créez une interface TicketState avec une méthode Handle(t *Ticket) string qui traite le ticket et le fait éventuellement passer à l'état suivant.

    Implémentez trois états :

    • OpenState : lorsqu'il est traité, fait passer le ticket à InProgressState et renvoie Ticket opened, assigning to support team
    • InProgressState : lorsqu'il est traité, fait passer le ticket à ResolvedState et renvoie Working on ticket, issue resolved
    • ResolvedState : lorsqu'il est traité, reste dans le même état et renvoie Ticket already resolved
  • ticket.go : créez votre structure de ticket, qui contient l'état actuel et lui délègue le comportement.

    Construisez une structure Ticket avec un champ ID (string) et un champ state (TicketState). Ajoutez ces méthodes :

    • SetState(s TicketState) pour modifier l'état actuel du ticket
    • Process() string qui délègue le traitement à la méthode Handle de l'état actuel

    Créez un constructeur NewTicket(id string) *Ticket qui renvoie un ticket commençant dans l'état OpenState.

  • main.go : montrez comment une même action produit des résultats différents selon l'état actuel du ticket.

    Lisez l'identifiant d'un ticket ainsi que le nombre de fois où le ticket doit être traité. Créez un nouveau ticket avec cet identifiant, puis appelez Process() le nombre de fois indiqué, en affichant chaque résultat sur une ligne distincte.

Les entrées suivantes seront fournies :

  • Ligne 1 : identifiant du ticket
  • Ligne 2 : nombre de fois où traiter le ticket

Par exemple, étant donné :

TKT-001
3

Votre sortie doit être :

Ticket opened, assigning to support team
Working on ticket, issue resolved
Ticket already resolved

Et étant donné :

TKT-500
5

Votre sortie doit être :

Ticket opened, assigning to support team
Working on ticket, issue resolved
Ticket already resolved
Ticket already resolved
Ticket already resolved

Et étant donné :

ISSUE-42
1

Votre sortie doit être :

Ticket opened, assigning to support team

Remarquez qu'appeler Process() sur le même ticket produit des résultats différents à chaque fois : le comportement du ticket change à mesure qu'il passe d'un état à l'autre. Une fois résolu, il reste résolu, quel que soit le nombre de fois où vous le traitez. L'objet ticket semble modifier son comportement, mais en réalité, il délègue ce comportement à différents objets d'état !

Essayez vous-même

package main

import (
	"fmt"
)

func main() {
	// Lire l'entrée
	var ticketID string
	var numProcesses int
	fmt.Scanln(&ticketID)
	fmt.Scanln(&numProcesses)

	// TODO: Créer un nouveau ticket avec l'ID donné

	// TODO: Traiter le ticket le nombre de fois spécifié
	// et imprimer chaque résultat sur une ligne séparée
}
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 Go en ligne