Menu
Coddy logo textTech

Patron Strategy

Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy — leçon 90 sur 107.

Le patron Stratégie (Strategy pattern) vous permet de définir une famille d'algorithmes, d'encapsuler chacun d'eux et de les rendre interchangeables au moment de l'exécution. Contrairement au patron Observateur où plusieurs objets réagissent à un seul événement, le patron Stratégie permet à un seul objet de basculer dynamiquement entre différents comportements.

En Go, nous implémentons le pattern Strategy en définissant une interface pour l'algorithme et en injectant différentes implémentations dans une structure de contexte (context struct) :

type PaymentStrategy interface {
    Pay(amount float64) string
}

type CreditCard struct{}
func (c CreditCard) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f via Credit Card", amount)
}

type PayPal struct{}
func (p PayPal) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f via PayPal", amount)
}

La structure de contexte détient une référence à l'interface de stratégie, permettant à l'algorithme d'être interchangé sans modifier le code du contexte :

type Checkout struct {
    strategy PaymentStrategy
}

func (c *Checkout) SetStrategy(s PaymentStrategy) {
    c.strategy = s
}

func (c *Checkout) ProcessPayment(amount float64) string {
    return c.strategy.Pay(amount)
}

Maintenant, vous pouvez changer la méthode de paiement au moment de l'exécution :

checkout := &Checkout{}

checkout.SetStrategy(CreditCard{})
fmt.Println(checkout.ProcessPayment(100.00))  // Payé 100.00 via Carte de Crédit

checkout.SetStrategy(PayPal{})
fmt.Println(checkout.ProcessPayment(50.00))   // Payé 50.00 via PayPal

Le modèle Strategy est idéal lorsque vous disposez de plusieurs façons d'effectuer une opération et que vous devez en sélectionner une en fonction de la saisie de l'utilisateur, de la configuration ou des conditions d'exécution. Les cas d'utilisation courants incluent les algorithmes de tri, les méthodes de compression et les règles de validation.

challenge icon

Défi

Facile

Construisons un système de formatage de texte en utilisant le patron de conception Strategy ! Vous allez créer différentes stratégies de formatage qui peuvent être interchangées au moment de l'exécution, permettant au même processeur de texte de produire différents styles de sortie sans modifier son code de base.

Vous organiserez votre code sur trois fichiers :

  • formatter.go : Définissez votre interface de stratégie et les stratégies de formatage concrètes.

    Créez une interface TextFormatter avec une méthode Format(text string) string qui transforme le texte selon les règles de la stratégie.

    Implémentez trois stratégies de formatage :

    • UppercaseFormatter — convertit le texte en majuscules
    • SnakeCaseFormatter — remplace les espaces par des underscores et met le texte en minuscules
    • TitleFormatter — met en majuscule la première lettre de chaque mot (les mots sont séparés par des espaces)
  • processor.go : Créez votre structure de contexte qui utilise la stratégie de formatage.

    Construisez une structure TextProcessor qui contient une stratégie TextFormatter. Ajoutez ces méthodes :

    • SetFormatter(f TextFormatter) pour changer la stratégie de formatage active
    • Process(text string) string qui applique le formateur actuel au texte

    Créez également un constructeur NewTextProcessor() qui retourne un processeur sans formateur initial défini.

  • main.go : Démontrez le changement de stratégies au moment de l'exécution.

    Lisez un texte, puis lisez un nombre d'opérations de formatage. Pour chaque opération, lisez le type de format (upper, snake, ou title), définissez le formateur approprié sur votre processeur, traitez le texte original et affichez le résultat.

Les entrées suivantes seront fournies :

  • Ligne 1 : Le texte à formater
  • Ligne 2 : Le nombre d'opérations de formatage
  • Lignes suivantes : Le type de format pour chaque opération

Par exemple, avec :

hello world today
3
upper
snake
title

Votre sortie devrait être :

HELLO WORLD TODAY
hello_world_today
Hello World Today

Et avec :

Go Programming Language
2
snake
upper

Votre sortie devrait être :

go_programming_language
GO PROGRAMMING LANGUAGE

Et avec :

design patterns are useful
1
title

Votre sortie devrait être :

Design Patterns Are Useful

Remarquez comment le même TextProcessor produit des sorties complètement différentes simplement en changeant sa stratégie de formateur. Le processeur ne sait pas et ne se soucie pas du formateur spécifique qu'il utilise — il délègue simplement à la stratégie qui est actuellement définie !

Aide-mémoire

Le pattern Strategy définit une famille d'algorithmes, encapsule chacun d'eux et les rend interchangeables au moment de l'exécution. Il permet à un seul objet de basculer dynamiquement entre différents comportements.

Définissez une interface pour l'algorithme :

type PaymentStrategy interface {
    Pay(amount float64) string
}

Implémentez des stratégies concrètes :

type CreditCard struct{}
func (c CreditCard) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f via Credit Card", amount)
}

type PayPal struct{}
func (p PayPal) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f via PayPal", amount)
}

Créez une structure de contexte qui contient une référence à l'interface de stratégie :

type Checkout struct {
    strategy PaymentStrategy
}

func (c *Checkout) SetStrategy(s PaymentStrategy) {
    c.strategy = s
}

func (c *Checkout) ProcessPayment(amount float64) string {
    return c.strategy.Pay(amount)
}

Changez de stratégie au moment de l'exécution :

checkout := &Checkout{}

checkout.SetStrategy(CreditCard{})
fmt.Println(checkout.ProcessPayment(100.00))  // Payé 100.00 via Credit Card

checkout.SetStrategy(PayPal{})
fmt.Println(checkout.ProcessPayment(50.00))   // Payé 50.00 via PayPal

Le pattern Strategy est idéal lorsque vous avez plusieurs façons d'effectuer une opération et que vous devez en sélectionner une en fonction de la saisie de l'utilisateur, de la configuration ou des conditions d'exécution.

Essayez vous-même

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Lire le texte à formater
	text, _ := reader.ReadString('\n')
	text = strings.TrimSpace(text)
	
	// Lire le nombre d'opérations
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))
	
	// Créer un nouveau processeur de texte
	processor := NewTextProcessor()
	
	// Traiter chaque opération de formatage
	for i := 0; i < count; i++ {
		formatType, _ := reader.ReadString('\n')
		formatType = strings.TrimSpace(formatType)
		
		// TODO: Selon le formatType ("upper", "snake", ou "title"),
		// définir le formateur approprié sur le processeur
		// et afficher le texte traité
		
	}
}
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