Patron Abstract Factory
Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy — leçon 88 sur 107.
Le pattern Abstract Factory étend le pattern Factory en créant des familles d'objets apparentés sans spécifier leurs types concrets. Au lieu d'une seule fonction de fabrique, vous définissez une interface de fabrique que plusieurs fabriques concrètes implémentent, chacune produisant un ensemble cohérent d'objets apparentés.
Considérez une boîte à outils d'interface utilisateur qui doit créer des boutons et des cases à cocher. Différents systèmes d'exploitation nécessitent des implémentations différentes, mais les composants doivent fonctionner ensemble de manière cohérente :
type Button interface {
Render() string
}
type Checkbox interface {
Check() string
}
// Interface de fabrique abstraite
type GUIFactory interface {
CreateButton() Button
CreateCheckbox() Checkbox
}Chaque fabrique concrète produit une famille de composants apparentés :
// Famille Windows
type WindowsButton struct{}
func (w WindowsButton) Render() string { return "Windows Button" }
type WindowsCheckbox struct{}
func (w WindowsCheckbox) Check() string { return "Windows Checkbox" }
type WindowsFactory struct{}
func (w WindowsFactory) CreateButton() Button { return WindowsButton{} }
func (w WindowsFactory) CreateCheckbox() Checkbox { return WindowsCheckbox{} }
// Famille Mac
type MacButton struct{}
func (m MacButton) Render() string { return "Mac Button" }
type MacCheckbox struct{}
func (m MacCheckbox) Check() string { return "Mac Checkbox" }
type MacFactory struct{}
func (m MacFactory) CreateButton() Button { return MacButton{} }
func (m MacFactory) CreateCheckbox() Checkbox { return MacCheckbox{} }Le code client travaille avec l'interface de la fabrique, tout en restant indépendant des implémentations concrètes :
func BuildUI(factory GUIFactory) {
button := factory.CreateButton()
checkbox := factory.CreateCheckbox()
fmt.Println(button.Render(), checkbox.Check())
}Utilisez Abstract Factory lorsque votre système doit fonctionner avec plusieurs familles de produits apparentés et que vous souhaitez vous assurer que les composants d'une même famille sont utilisés ensemble. C'est plus complexe qu'une simple Factory, ne l'utilisez donc que lorsque vous avez réellement besoin de gérer des familles de produits.
Défi
FacileConstruisons un système de magasin de meubles en utilisant le motif Abstract Factory ! Vous allez créer des usines qui produisent des familles d'articles de mobilier apparentés — chaque usine produit un style cohérent (Modern ou Vintage), garantissant que les chaises et les tables de la même usine s'accordent esthétiquement.
Vous organiserez votre code sur trois fichiers :
furniture.go: Définissez vos interfaces de produits et vos types de meubles concrets.Créez deux interfaces de produits :
Chairavec une méthodeSitOn() stringTableavec une méthodePlaceItems() string
Implémentez deux familles de meubles :
- Famille Modern :
ModernChairretourne"Sitting on a sleek modern chair"etModernTableretourne"Placing items on a glass modern table" - Famille Vintage :
VintageChairretourne"Sitting on an ornate vintage chair"etVintageTableretourne"Placing items on a wooden vintage table"
factory.go: Définissez votre interface d'usine abstraite et vos usines concrètes.Créez une interface
FurnitureFactoryavec deux méthodes :CreateChair() ChairCreateTable() Table
Implémentez deux usines concrètes :
ModernFactoryqui produitModernChairetModernTableVintageFactoryqui produitVintageChairetVintageTable
Créez également une fonction
GetFactory(style string) FurnitureFactoryqui retourne l'usine appropriée en fonction du style ("modern"ou"vintage"). UtilisezModernFactorypar défaut pour les styles non reconnus.main.go: Utilisez vos usines pour meubler des pièces.Créez une fonction
FurnishRoom(factory FurnitureFactory) stringqui utilise l'usine pour créer une chaise et une table, puis retourne une chaîne formatée montrant les deux actions sur des lignes séparées.Lisez une entrée de style, obtenez l'usine appropriée, meublez une pièce et affichez le résultat.
Les entrées suivantes seront fournies :
- Ligne 1 : Style de meuble (
"modern","vintage", ou autre chose)
Par exemple, avec :
modernVotre sortie devrait être :
Sitting on a sleek modern chair
Placing items on a glass modern tableEt avec :
vintageVotre sortie devrait être :
Sitting on an ornate vintage chair
Placing items on a wooden vintage tableEt avec :
rusticVotre sortie devrait être :
Sitting on a sleek modern chair
Placing items on a glass modern tableRemarquez comment la fonction FurnishRoom fonctionne avec n'importe quelle usine via l'interface — elle ne sait pas si elle crée des meubles modernes ou vintage. Cela garantit que tous les meubles d'une pièce proviennent de la même famille, maintenant ainsi un style cohérent !
Aide-mémoire
Le pattern Abstract Factory (ou Fabrique Abstraite) crée des familles d'objets apparentés sans spécifier leurs types concrets. Il définit une interface de fabrique que plusieurs fabriques concrètes implémentent, chacune produisant un ensemble cohérent d'objets apparentés.
Structure
Définissez des interfaces de produit pour chaque type d'objet :
type Button interface {
Render() string
}
type Checkbox interface {
Check() string
}Créez une interface de fabrique abstraite qui déclare des méthodes pour créer chaque type de produit :
type GUIFactory interface {
CreateButton() Button
CreateCheckbox() Checkbox
}Implémentations concrètes
Implémentez des familles de produits concrètes où chaque famille a un style ou un comportement cohérent :
// Famille Windows
type WindowsButton struct{}
func (w WindowsButton) Render() string { return "Windows Button" }
type WindowsCheckbox struct{}
func (w WindowsCheckbox) Check() string { return "Windows Checkbox" }
type WindowsFactory struct{}
func (w WindowsFactory) CreateButton() Button { return WindowsButton{} }
func (w WindowsFactory) CreateCheckbox() Checkbox { return WindowsCheckbox{} }
// Famille Mac
type MacButton struct{}
func (m MacButton) Render() string { return "Mac Button" }
type MacCheckbox struct{}
func (m MacCheckbox) Check() string { return "Mac Checkbox" }
type MacFactory struct{}
func (m MacFactory) CreateButton() Button { return MacButton{} }
func (m MacFactory) CreateCheckbox() Checkbox { return MacCheckbox{} }Code client
Le code client travaille avec l'interface de la fabrique, restant indépendant des implémentations concrètes :
func BuildUI(factory GUIFactory) {
button := factory.CreateButton()
checkbox := factory.CreateCheckbox()
fmt.Println(button.Render(), checkbox.Check())
}Quand l'utiliser
Utilisez l'Abstract Factory lorsque votre système doit fonctionner avec plusieurs familles de produits apparentés et que vous souhaitez garantir que les composants d'une même famille sont utilisés ensemble. C'est plus complexe qu'une simple Factory, ne l'utilisez donc que lorsque vous avez réellement besoin de gérer des familles de produits.
Essayez vous-même
package main
import "fmt"
// FurnishRoom utilise une fabrique pour créer des meubles et retourne le résultat
// TODO: Implémenter cette fonction
// - Utiliser la fabrique pour créer une chaise et une table
// - Retourner une chaîne avec le résultat de SitOn() sur la première ligne et le résultat de PlaceItems() sur la deuxième ligne
func FurnishRoom(factory FurnitureFactory) string {
// TODO: Créer une chaise et une table en utilisant la fabrique
// TODO: Retourner une chaîne formatée avec les deux actions sur des lignes séparées
return ""
}
func main() {
var style string
fmt.Scanln(&style)
// TODO: Obtenir la fabrique appropriée en fonction du style
// TODO: Meubler une pièce en utilisant la fabrique
// TODO: Afficher le résultat
}
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