Modèle Composite
Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy. Leçon 96 sur 107.
Le patron Composite vous permet de traiter uniformément les objets individuels et les groupes d’objets. Alors que State modifie le comportement en fonction de l’état interne, Composite construit des structures arborescentes dans lesquelles les feuilles et les conteneurs partagent la même interface.
Ce modèle est parfait pour les structures hiérarchiques telles que les systèmes de fichiers, les organigrammes ou les composants d’interface utilisateur. En Go, nous définissons une interface commune que les éléments individuels et les conteneurs implémentent :
type Component interface {
GetSize() int
}
type File struct {
Name string
Size int
}
func (f File) GetSize() int {
return f.Size
}Le composite (conteneur) contient des enfants et implémente la même interface en agrégeant leurs résultats :
type Folder struct {
Name string
Children []Component
}
func (f *Folder) Add(c Component) {
f.Children = append(f.Children, c)
}
func (f Folder) GetSize() int {
total := 0
for _, child := range f.Children {
total += child.GetSize()
}
return total
}Vous pouvez maintenant imbriquer des dossiers dans des dossiers, et l’appel de GetSize() fonctionne de manière identique, qu’il s’agisse d’un seul fichier ou d’une arborescence de répertoires entière :
docs := &Folder{Name: "docs"}
docs.Add(File{Name: "readme.txt", Size: 100})
docs.Add(File{Name: "notes.txt", Size: 50})
root := &Folder{Name: "root"}
root.Add(docs)
root.Add(File{Name: "config.json", Size: 25})
fmt.Println(root.GetSize()) // 175Le modèle Composite est idéal lorsque vous devez représenter des hiérarchies partie-tout et que vous voulez que les clients traitent les objets individuels et les compositions de manière identique.
Défi
FacileConstruisons un système d’organigramme en utilisant le pattern Composite ! Vous allez créer une structure dans laquelle les employés individuels et les départements (qui contiennent des employés ou d’autres départements) peuvent être traités uniformément, ce qui est idéal pour calculer les salaires totaux de n’importe quelle partie de l’organisation.
Vous allez organiser votre code dans trois fichiers :
component.go: définissez l’interface commune que les individus et les groupes implémenteront.Créez une interface
OrgComponentavec deux méthodes :GetSalary() int: renvoie le salaire total de ce composantGetName() string: renvoie le nom de l’employé ou du département
organization.go: implémentez les types feuille (employé individuel) et composite (département).Créez une structure
Employeeavec les champsName(string) etSalary(int). SonGetSalary()renvoie son propre salaire, etGetName()renvoie son nom.Créez une structure
Departmentavec un champName(string) et une trancheMemberscontenant des élémentsOrgComponent. Ajoutez une méthodeAdd(c OrgComponent)pour ajouter des membres. SonGetSalary()doit renvoyer la somme des salaires de tous les membres, etGetName()renvoie le nom du département.main.go: construisez une structure organisationnelle et calculez les salaires.Lisez le nombre d’employés. Pour chaque employé, lisez son nom et son salaire en créant des instances de
Employee. Lisez ensuite le nombre de départements. Pour chaque département, lisez son nom et le nombre d’indices de membres, puis ces indices (en base 0, faisant référence aux employés ou départements précédemment créés, dans leur ordre de création).Après avoir construit la structure, lisez un indice final et affichez le nom et le salaire total de ce composant au format :
[name]: [salary]
Les entrées suivantes seront fournies :
- Le nombre d’employés, puis le nom et le salaire de chaque employé sur des lignes séparées
- Le nombre de départements, puis le nom de chaque département, le nombre de membres et les indices des membres
- L’indice final à interroger
Par exemple, étant donné :
3
Alice
50000
Bob
60000
Carol
55000
1
Engineering
3
0
1
2
3Votre sortie doit être :
Engineering: 165000Et étant donné :
4
Alice
50000
Bob
60000
Carol
55000
Dave
70000
2
Dev
2
0
1
QA
2
2
3
4Votre sortie doit être :
QA: 125000Et étant donné :
2
Alice
50000
Bob
60000
0
1Votre sortie doit être :
Bob: 60000Remarquez que GetSalary() fonctionne de manière identique, que vous l’appeliez sur un seul employé ou sur un département entier : le pattern Composite vous permet de traiter uniformément les individus et les groupes au moyen de la même interface !
Essayez vous-même
package main
import "fmt"
func main() {
// Lire le nombre d'employés
var numEmployees int
fmt.Scanln(&numEmployees)
// Stocker tous les composants (employés et départements) dans l'ordre de création
var components []OrgComponent
// TODO: Lire le nom et le salaire de chaque employé
// Créer des instances Employee et les ajouter au slice components
for i := 0; i < numEmployees; i++ {
var name string
var salary int
fmt.Scanln(&name)
fmt.Scanln(&salary)
// TODO: Créer l'employé et l'ajouter à components
}
// Lire le nombre de départements
var numDepartments int
fmt.Scanln(&numDepartments)
// TODO: Lire le nom de chaque département, le nombre de membres et les indices des membres
// Créer des instances Department, ajouter les membres par index, et ajouter à components
for i := 0; i < numDepartments; i++ {
var deptName string
var memberCount int
fmt.Scanln(&deptName)
fmt.Scanln(&memberCount)
// TODO: Créer le département, lire les indices des membres, ajouter les membres, ajouter à components
}
// Lire l'index final à interroger
var queryIndex int
fmt.Scanln(&queryIndex)
// TODO: Afficher le nom du composant et le salaire total au format : [name]: [salary]
// Exemple: fmt.Printf("%s: %d\n", name, salary)
}
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 et non exportésIntroduction à la POO en GoStructs comme classesDéfinir des méthodes sur des structsRécepteurs pointeurs ou par valeurInitialisation des structsFonctions constructeursRécapitulatif - Calculatrice simple4Interfaces
Introduction aux interfacesImplémentation impliciteL’interface comme contratInterface vide (any)Assertion de typeCommutation de typeComposition d’interfacesInterfaces Stringer et ErrorRécapitulatif - Calculateur de formes7Encapsulation
Champs exportés vs non exportésEncapsulation au niveau du packageMéthodes Getter et SetterDissimulation de l’information en GoRécapitulatif – Fiches d’étudiants10Génériques (Go 1.18+)
Introduction aux génériquesParamètres de typeContraintes de typeStructures génériquesSolution de contournement pour les méthodes génériquesRécapitulatif - Collection générique2Plongée approfondie dans les types et les structs
Types de base et compositesDéfinitions de types personnalisésTags de structStructs anonymesStructs imbriquésValeurs zéro et valeurs par défautRécapitulatif - Carnet de contacts5La composition plutôt que l’héritage
Pourquoi Go n’a pas d’héritageBases de l’inclusion de structsPromotion des méthodesInclure plusieurs structsInclusion ou agrégationMasquage des méthodes inclusesRécapitulatif : hiérarchie des employés8Gestion des erreurs et POO
L’interface errorTypes d’erreurs personnalisésEnrobage des erreurs (fmt.Errorf)Erreurs sentinelleserrors.Is() et errors.As()Panic, Defer et RecoverRécapitulatif - Analyseur de fichiers11Bibliothèque standard et POO
io.Reader et io.Writersort.InterfaceInterface fmt.Stringerencoding/json avec des structsInterface http.HandlerRécapitulatif - Modèles d’API REST14Modèles de conception – Partie 2
Modèle CommandeModèle AdaptateurModèle DécorateurModèle Méthode modèleModèle ÉtatModèle CompositeMiddleware comme décorateur3Pointeurs et mémoire
Notions de base des pointeurs en GoPointeurs vers des structuresPassage par valeur ou par référenceLa fonction new()Garbage collection en GoRécapitulatif - Constructeur de listes chaînées6Polymorphisme en Go
Polymorphisme via les interfacesDuck typing en GoRègles de satisfaction des interfacesCollections polymorphesInjection de dépendancesRécapitulatif – Processeur de paiements9Concurrence et POO
Bases des GoroutinesCanaux et communicationCanaux tamponnés ou non tamponnésInstruction selectsync.Mutex et sync.RWMutexsync.WaitGroupConception de structures thread-safeRécapitulatif - Pool de workersEntraînez-vous par vous-même : Compilateur Go en ligne