Introduction aux Design Patterns
Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy — leçon 85 sur 107.
Les patrons de conception (design patterns) sont des solutions réutilisables aux problèmes courants qui surviennent lors de la conception de logiciels. Ce ne sont pas des morceaux de code que vous copiez directement, mais plutôt des modèles qui guident la manière dont vous structurez vos types et leurs interactions pour résoudre des défis spécifiques.
Les patrons de conception sont généralement regroupés en trois catégories :
| Catégorie | Objectif | Exemples |
|---|---|---|
| Création | Mécanismes de création d'objets | Singleton, Factory, Builder |
| Structure | Composition de types en structures plus larges | Adapter, Decorator, Composite |
| Comportement | Communication entre les objets | Observer, Strategy, Command |
En Go, les patrons de conception sont différents de ceux des langages de POO traditionnels.
Sans classes ni héritage, Go implémente des modèles en utilisant des interfaces, l'imbrication de structures (struct embedding) et la composition. Par exemple, là où Java pourrait utiliser une classe abstraite, Go utilise une interface. Là où C++ pourrait utiliser l'héritage, Go utilise l'imbrication.
Apprendre les patrons de conception vous aide à reconnaître les problèmes courants et à communiquer des solutions efficacement avec d'autres développeurs. Quand quelqu'un mentionne « utilisez le patron Stratégie ici », toute l'équipe comprend l'approche sans explications interminables.
Au cours des prochaines leçons, vous implémenterez plusieurs patrons fondamentaux en Go, en commençant par les patrons de création tels que Singleton et Factory, puis en passant aux patrons de comportement tels que Observer et Strategy.
Défi
FacileConstruisons un système de notification simple qui démontre comment les patrons de conception aident à organiser le code ! Vous allez créer une structure qui pourrait facilement être étendue avec des patrons comme Observer ou Strategy dans de futures leçons—mais pour l'instant, concentrez-vous sur la mise en place d'interfaces et de types propres qui suivent les bons principes de la POO.
Vous organiserez votre code sur trois fichiers :
notifier.go: Définissez l'interface principale et les types pour votre système de notification.Créez une interface
Notifieravec une seule méthodeSend(message string) stringqui retourne un message de confirmation.Implémentez deux types de notificateurs concrets :
EmailNotifieravec un champAddress—sa méthodeSendretourneEmail to [address]: [message]SMSNotifieravec un champPhoneNumber—sa méthodeSendretourneSMS to [phone]: [message]
dispatcher.go: Créez un répartiteur qui fonctionne avec n'importe quel notificateur via l'interface.Construisez une structure
NotificationDispatcherqui contient une tranche (slice) d'interfacesNotifier. Ajoutez ces méthodes :AddNotifier(n Notifier)pour enregistrer un notificateurBroadcast(message string) []stringqui envoie le message via tous les notificateurs enregistrés et retourne une tranche de toutes les chaînes de confirmation
Créez également un constructeur
NewNotificationDispatcher()qui retourne un répartiteur initialisé.main.go: Configurez les notificateurs et diffusez les messages.Lisez un nombre de notificateurs à créer. Pour chaque notificateur, lisez son type (
emailousms) et sa destination (adresse ou numéro de téléphone). Ajoutez chacun à un répartiteur.Ensuite, lisez un message à diffuser. Envoyez-le via tous les notificateurs et affichez chaque confirmation sur sa propre ligne.
Les entrées suivantes seront fournies :
- Ligne 1 : Nombre de notificateurs
- Pour chaque notificateur : type (
emailousms), puis destination - Dernière ligne : Message à diffuser
Par exemple, avec :
3
email
alice@example.com
sms
555-1234
email
bob@example.com
Server maintenance at midnightVotre sortie devrait être :
Email to alice@example.com: Server maintenance at midnight
SMS to 555-1234: Server maintenance at midnight
Email to bob@example.com: Server maintenance at midnightEt avec :
2
sms
555-9999
sms
555-0000
Meeting canceledVotre sortie devrait être :
SMS to 555-9999: Meeting canceled
SMS to 555-0000: Meeting canceledCette structure démontre comment les interfaces permettent des conceptions flexibles et extensibles. Le répartiteur ne connaît pas les types de notificateurs spécifiques—il sait simplement qu'ils peuvent Send. C'est la base sur laquelle reposent des patrons comme Observer et Strategy !
Aide-mémoire
Les patrons de conception (design patterns) sont des solutions réutilisables à des problèmes courants de conception logicielle. Ce sont des modèles qui guident la manière de structurer les types et leurs interactions.
Les patrons de conception sont regroupés en trois catégories :
| Catégorie | Objectif | Exemples |
|---|---|---|
| Création | Mécanismes de création d'objets | Singleton, Factory, Builder |
| Structurel | Composition de types en structures plus larges | Adapter, Decorator, Composite |
| Comportemental | Communication entre objets | Observer, Strategy, Command |
En Go, les patrons de conception sont implémentés en utilisant des interfaces, l'imbrication de structures (struct embedding) et la composition au lieu des classes et de l'héritage. Là où les langages de POO traditionnels utilisent des classes abstraites, Go utilise des interfaces. Là où ils utilisent l'héritage, Go utilise l'imbrication.
Essayez vous-même
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Lire le nombre de notificateurs
countStr, _ := reader.ReadString('\n')
count, _ := strconv.Atoi(strings.TrimSpace(countStr))
// Créer un nouveau dispatcher
dispatcher := NewNotificationDispatcher()
// Lire chaque notificateur et l'ajouter au dispatcher
for i := 0; i < count; i++ {
notifierType, _ := reader.ReadString('\n')
notifierType = strings.TrimSpace(notifierType)
destination, _ := reader.ReadString('\n')
destination = strings.TrimSpace(destination)
// TODO: Créer le notificateur approprié en fonction du type
// et l'ajouter au dispatcher
// Hint: Vérifier si notifierType est "email" ou "sms"
}
// Lire le message à diffuser
message, _ := reader.ReadString('\n')
message = strings.TrimSpace(message)
// TODO: Diffuser le message et afficher chaque confirmation
}
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 Pool