Menu
Coddy logo textTech

Modèle Méthode modèle

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

Le pattern Template Method définit la structure d’un algorithme dans un type de base, permettant aux sous-types de redéfinir certaines étapes sans modifier la structure globale. Alors que Decorator ajoute un comportement en enveloppant des objets, Template Method contrôle le déroulement de l’algorithme et permet de personnaliser chaque étape.

En Go, puisqu'il n'y a pas d'héritage, nous implémentons ce modèle à l'aide de l'intégration de structures combinée à des interfaces. La structure « modèle » définit la structure de l'algorithme et appelle des méthodes qui peuvent être personnalisées :

type DataProcessor interface {
    ReadData() string
    ProcessData(data string) string
    SaveData(result string) string
}

type BaseProcessor struct {
    Impl DataProcessor
}

func (b *BaseProcessor) Execute() string {
    data := b.Impl.ReadData()
    result := b.Impl.ProcessData(data)
    return b.Impl.SaveData(result)
}

Les implémentations concrètes fournissent leurs propres versions de chaque étape, tandis que le déroulement de l’algorithme reste inchangé :

type CSVProcessor struct{}

func (c CSVProcessor) ReadData() string       { return "csv-data" }
func (c CSVProcessor) ProcessData(d string) string { return "processed-" + d }
func (c CSVProcessor) SaveData(r string) string    { return "Saved: " + r }

type JSONProcessor struct{}

func (j JSONProcessor) ReadData() string       { return "json-data" }
func (j JSONProcessor) ProcessData(d string) string { return "parsed-" + d }
func (j JSONProcessor) SaveData(r string) string    { return "Stored: " + r }

La méthode de modèle Execute orchestre les étapes dans un ordre fixe :

csvProc := &BaseProcessor{Impl: CSVProcessor{}}
fmt.Println(csvProc.Execute())  // Enregistré : processed-csv-data

jsonProc := &BaseProcessor{Impl: JSONProcessor{}}
fmt.Println(jsonProc.Execute()) // Stocké : parsed-json-data

Template Method est idéal lorsque vous avez des algorithmes qui partagent la même structure, mais qui diffèrent par certaines étapes, comme les pipelines d’importation/exportation de données, les générateurs de rapports ou les frameworks de test.

challenge icon

Défi

Facile

Construisons un système de génération de rapports à l’aide du patron Template Method ! Vous allez créer un framework dans lequel différents types de rapports suivent le même processus de génération : collecte des données, mise en forme et production du résultat, tout en permettant à chaque type de rapport de personnaliser ces étapes différemment.

Vous allez organiser votre code dans trois fichiers :

  • report.go : définissez votre interface et le processeur de base qui orchestre l’algorithme de génération du rapport.

    Créez une interface ReportGenerator avec trois méthodes représentant les étapes de la génération du rapport :

    • GatherData() string : récupère les données brutes du rapport
    • FormatData(data string) string : transforme les données au format du rapport
    • OutputReport(formatted string) string : produit le message de sortie final

    Construisez une structure ReportProcessor qui contient une implémentation de ReportGenerator. Ajoutez une méthode Generate() string qui exécute les trois étapes dans l’ordre : collecte, mise en forme, puis sortie, et renvoie le résultat final.

  • generators.go : implémentez les générateurs de rapports concrets qui personnalisent chaque étape.

    Créez deux types de rapports :

    • SalesReport avec un champ Region (chaîne de caractères)
      • GatherData() renvoie sales-data-[region]
      • FormatData(data) renvoie SALES REPORT: [data]
      • OutputReport(formatted) renvoie Printed: [formatted]
    • InventoryReport avec un champ Warehouse (chaîne de caractères)
      • GatherData() renvoie inventory-[warehouse]
      • FormatData(data) renvoie *** [data] ***
      • OutputReport(formatted) renvoie Exported: [formatted]
  • main.go : montrez comment la même structure algorithmique produit des résultats différents selon l’implémentation.

    Lisez le type de rapport (sales ou inventory) ainsi que la valeur de configuration (la région pour sales, l’entrepôt pour inventory). Créez le générateur approprié, encapsulez-le dans un ReportProcessor, appelez Generate() et affichez le résultat.

Les entrées suivantes seront fournies :

  • Ligne 1 : type de rapport (sales ou inventory)
  • Ligne 2 : valeur de configuration (nom de la région ou nom de l’entrepôt)

Par exemple, avec :

sales
North

Votre sortie doit être :

Printed: SALES REPORT: sales-data-North

Et avec :

inventory
MainHub

Votre sortie doit être :

Exported: *** inventory-MainHub ***

Et avec :

sales
West

Votre sortie doit être :

Printed: SALES REPORT: sales-data-West

Remarquez que ReportProcessor appelle toujours les mêmes trois étapes dans le même ordre, mais que chaque type de rapport fournit sa propre implémentation de ces étapes. L’ossature de l’algorithme reste fixe tandis que les détails varient : c’est le patron Template Method en action !

Essayez vous-même

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Lire le type de rapport
	scanner.Scan()
	reportType := scanner.Text()
	
	// Lire la valeur de configuration (région ou entrepôt)
	scanner.Scan()
	configValue := scanner.Text()

	// TODO: Créer le générateur approprié en fonction de reportType
	// - Si reportType est "sales", créer un SalesReport avec Region défini à configValue
	// - Si reportType est "inventory", créer un InventoryReport avec Warehouse défini à configValue
	
	// TODO: Créer un ReportProcessor avec le générateur
	
	// TODO: Appeler Generate() et afficher le résultat
	_ = reportType
	_ = configValue
	fmt.Println("TODO: Generate and print the report")
}
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