Chaînage de méthodes
Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy — leçon 81 sur 107.
Le chaînage de méthodes (method chaining) est une technique où les méthodes retournent le receveur, permettant de lier plusieurs appels de méthodes en une seule instruction. Vous avez déjà vu cela dans le patron Builder, mais c'est un concept autonome utile dans de nombreux contextes.
La clé est de retourner un pointeur vers la struct à partir de chaque méthode :
type Query struct {
table string
columns []string
where string
limit int
}
func (q *Query) Select(cols ...string) *Query {
q.columns = cols
return q
}
func (q *Query) From(table string) *Query {
q.table = table
return q
}
func (q *Query) Where(condition string) *Query {
q.where = condition
return q
}
func (q *Query) Limit(n int) *Query {
q.limit = n
return q
}Maintenant, vous pouvez chaîner ces appels de manière fluide :
query := &Query{}
query.Select("name", "email").From("users").Where("active = true").Limit(10)Cela se lit presque comme du langage naturel par rapport à des instructions séparées. Le chaînage de méthodes fonctionne mieux lorsque les opérations configurent ou modifient un objet sans avoir besoin de renvoyer d'autres valeurs. Il est couramment utilisé dans les générateurs de requêtes, les API de configuration et les bibliothèques d'assertions de test.
N'oubliez pas que chaque méthode doit utiliser un récepteur de pointeur et retourner *StructType pour que le chaînage fonctionne correctement.
Défi
FacileConstruisons un générateur d'éléments HTML fluide qui utilise le chaînage de méthodes pour construire des balises HTML avec des attributs et du contenu ! Il s'agit d'une application pratique du chaînage de méthodes — vous allez créer une API qui se lit presque comme un langage naturel lors de la construction d'éléments HTML.
Vous organiserez votre code sur deux fichiers :
element.go: Définissez votre générateur d'éléments HTML avec des méthodes chaînables.Créez une structure
Elementqui stocke le nom de la balise, une map d'attributs (chaîne vers chaîne) et le contenu interne. Construisez ces méthodes chaînables qui retournent chacune*Element:NewElement(tag string)- constructeur qui crée un nouvel Element avec le nom de balise donné et une map d'attributs initialisée (vide)Attr(key, value string)- ajoute un attribut à l'élémentID(id string)- méthode de commodité qui définit l'attribut "id"Class(class string)- méthode de commodité qui définit l'attribut "class"Content(text string)- définit le contenu interne de l'élément
Ajoutez une méthode
Render()qui retourne la chaîne HTML. Les attributs doivent apparaître par ordre alphabétique de clé. Le format est :<tag attr1="value1" attr2="value2">content</tag>S'il n'y a pas d'attributs, affichez simplement
<tag>content</tag>. S'il n'y a pas de contenu, affichez<tag attr="value"></tag>.main.go: Construisez des éléments HTML en utilisant le chaînage de méthodes.Lisez le nom de la balise, puis lisez le nombre d'opérations à effectuer. Chaque opération est l'une des suivantes :
idsuivi de la valeur de l'IDclasssuivi de la valeur de la classeattrsuivi du nom de l'attribut et de sa valeur (deux lignes)contentsuivi du texte du contenu
Chaînez toutes les opérations ensemble de manière fluide, puis affichez le HTML généré.
Les entrées suivantes seront fournies :
- Ligne 1 : Nom de la balise
- Ligne 2 : Nombre d'opérations
- Lignes suivantes : Type d'opération et valeur(s)
Par exemple, avec :
div
3
id
container
class
main-content
content
Hello WorldVotre sortie devrait être :
<div class="main-content" id="container">Hello World</div>Et avec :
a
3
attr
href
https://example.com
attr
target
_blank
content
Click hereVotre sortie devrait être :
<a href="https://example.com" target="_blank">Click here</a>Et avec :
input
2
attr
type
text
attr
placeholder
Enter nameVotre sortie devrait être :
<input placeholder="Enter name" type="text"></input>Et avec :
p
1
content
Simple paragraphVotre sortie devrait être :
<p>Simple paragraph</p>Remarquez comment le chaînage de méthodes vous permet de construire des éléments étape par étape de manière lisible. Chaque méthode modifie l'élément et le retourne, permettant à l'appel de méthode suivant d'être chaîné directement.
Aide-mémoire
Le chaînage de méthodes est une technique où les méthodes retournent le récepteur (généralement *StructType), permettant à plusieurs appels de méthodes d'être liés ensemble dans une seule instruction.
Chaque méthode doit utiliser un récepteur de pointeur et retourner *StructType :
type Query struct {
table string
columns []string
where string
limit int
}
func (q *Query) Select(cols ...string) *Query {
q.columns = cols
return q
}
func (q *Query) From(table string) *Query {
q.table = table
return q
}
func (q *Query) Where(condition string) *Query {
q.where = condition
return q
}
func (q *Query) Limit(n int) *Query {
q.limit = n
return q
}Enchaînez les appels de méthodes de manière fluide :
query := &Query{}
query.Select("name", "email").From("users").Where("active = true").Limit(10)Le chaînage de méthodes fonctionne mieux lorsque les opérations configurent ou modifient un objet sans avoir besoin de retourner d'autres valeurs. Il est couramment utilisé dans les constructeurs de requêtes (query builders), les API de configuration et les bibliothèques d'assertions de test.
Essayez vous-même
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Lire le nom de la balise
scanner.Scan()
tagName := scanner.Text()
// Lire le nombre d'opérations
scanner.Scan()
numOps, _ := strconv.Atoi(scanner.Text())
// Créer l'élément
element := NewElement(tagName)
// Traiter chaque opération
for i := 0; i < numOps; i++ {
scanner.Scan()
operation := scanner.Text()
// TODO : Selon le type d'opération, enchaîner la méthode appropriée
// Les opérations peuvent être : "id", "class", "attr", ou "content"
// - Pour "id" : lire la ligne suivante comme valeur de l'ID
// - Pour "class" : lire la ligne suivante comme valeur de la classe
// - Pour "attr" : lire les DEUX lignes suivantes (nom de l'attribut, puis valeur)
// - Pour "content" : lire la ligne suivante comme texte du contenu
// Utiliser le chaînage de méthodes pour construire l'élément de manière fluide
_ = operation // Supprimer cette ligne lors de l'implémentation
}
// Afficher le HTML rendu
fmt.Println(element.Render())
}
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 en Go
Fichiers externesEspace de travail et Modules GoPackages et ImportsNoms exportés vs non exportésIntroduction à la POO en GoLes Structs comme ClassesDéfinir des méthodes sur les StructsReceveurs par pointeur vs par valeurInitialisation de StructsFonctions constructeursRécapitulatif - Calculatrice simple4Interfaces
Introduction aux interfacesImplémentation impliciteL'interface comme contratInterface vide (any)Assertion de typeType SwitchComposition d'interfacesInterfaces Stringer & ErrorRécapitulatif - Calculateur de formes7Encapsulation
Champs exportés vs non exportésEncapsulation au niveau du packageMéthodes Getter & SetterMasquage d'informations en GoRécapitulatif - Dossiers étudiants10Génériques (Go 1.18+)
Introduction aux génériquesParamètres de typeContraintes de typeStructures génériquesContournement pour les méthodes génériquesRécapitulatif - Collections génériques13Patrons de conception, Partie 1
Introduction aux Design PatternsPatron SingletonPatron FactoryPatron Abstract FactoryPatron ObserverPatron Strategy2Exploration approfondie des Types et Structs
Types de base et compositesDéfinitions de types personnalisésTags de StructStructs anonymesStructs imbriquéesValeurs par défaut et Zero ValuesRécapitulatif - Carnet de contacts5Composition plutôt qu'héritage
Pourquoi Go n'a pas d'héritageLes bases de l'imbrication de structsPromotion de méthodesImbriquer plusieurs structsImbrication vs AgrégationMasquage de méthodes imbriquéesRécapitulatif - Hiérarchie des employés8Gestion des erreurs & POO
L'interface errorTypes d'erreurs personnalisésError Wrapping (fmt.Errorf)Erreurs sentinelleserrors.Is() et errors.As()Panic, Defer et RecoverRécapitulatif - File Parser11Bibliothèque standard et POO
io.Reader & io.WriterL'interface sort.InterfaceL'interface fmt.Stringerencoding/json avec les StructsL'interface http.HandlerRécapitulatif - Modèles d'API REST14Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositeMiddleware en tant que Décorateur3Pointeurs et Mémoire
Bases des pointeurs en GoPointeurs vers des structsPassage par valeur vs référenceLa fonction new()Garbage Collection en GoRécapitulatif - Constructeur de liste chaînée6Le polymorphisme en Go
Le polymorphisme via les interfacesLe Duck Typing en GoRègles de satisfaction des interfacesCollections polymorphesInjection de dépendancesRécapitulatif - Processeur de paiement9Concurrence et POO
Bases des GoroutinesChannels et CommunicationChannels avec buffer vs sans bufferL'instruction Selectsync.Mutex et sync.RWMutexsync.WaitGroupConception de structures Thread-SafeRécapitulatif - Worker Pool12Concepts POO Avancés
Pattern Functional OptionsPattern Builder en GoChaînage de méthodesAlias de types vs DéfinitionsBases de la RéflexionAperçu de la génération de code