Menu
Coddy logo textTech

Pattern Strategy

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

Le pattern Strategy vous permet de définir une famille d’algorithmes, d’encapsuler chacun d’eux et de les rendre interchangeables à l’exécution. Contrairement à Observer, où plusieurs objets réagissent à un même événement, Strategy permet à un seul objet de basculer dynamiquement entre différents comportements.

En Go, nous implémentons Strategy en définissant une interface pour l’algorithme et en injectant différentes implémentations dans une structure de contexte :

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 contient une référence vers l’interface de stratégie, ce qui permet de remplacer l’algorithme 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)
}

Vous pouvez maintenant changer la méthode de paiement à 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 pattern 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 l’entrée utilisateur, de la configuration ou des conditions d’exécution. Parmi les cas d’utilisation courants figurent 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 utilisant le modèle Strategy ! Vous allez créer différentes stratégies de formatage qui peuvent être remplacées à l’exécution, ce qui permettra au même processeur de texte de produire différents styles de sortie sans modifier son code central.

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 entièrement en majuscules
    • SnakeCaseFormatter : remplace les espaces par des traits de soulignement et convertit 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 modifier la stratégie de formatage active
    • Process(text string) string qui applique le formateur actuel au texte

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

  • main.go : démontrez le changement de stratégie à l’exécution.

    Lisez un texte, puis lisez un nombre d’opérations de formatage. Pour chaque opération, lisez le type de formatage (upper, snake ou title), définissez le formateur approprié sur votre processeur, traitez le texte d’origine 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 formatage pour chaque opération

Par exemple, avec :

hello world today
3
upper
snake
title

Votre sortie doit être :

HELLO WORLD TODAY
hello_world_today
Hello World Today

Et avec :

Go Programming Language
2
snake
upper

Votre sortie doit être :

go_programming_language
GO PROGRAMMING LANGUAGE

Et avec :

design patterns are useful
1
title

Votre sortie doit être :

Design Patterns Are Useful

Remarquez comment le même TextProcessor produit des sorties complètement différentes simplement en remplaçant sa stratégie de formatage. Le processeur ne sait pas, et ne se soucie pas, de quel formateur spécifique il utilise. Il délègue simplement le traitement à la stratégie actuellement définie !

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: En fonction de formatType ("upper", "snake", or "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

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