Champs exportés vs non exportés
Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy. Leçon 47 sur 107.
En Go, l’encapsulation au niveau de la structure est contrôlée par la casse des noms de champs. Cette règle simple détermine si les champs peuvent être consultés depuis l’extérieur du paquet dans lequel la structure est définie.
Les champs commençant par une lettre majuscule sont exportés : accessibles depuis n’importe quel package. Les champs commençant par une lettre minuscule sont non exportés : accessibles uniquement au sein du même package :
// Dans le package "user"
type User struct {
Name string // Exporté - accessible partout
Email string // Exporté - accessible partout
password string // Non exporté - accessible uniquement dans le package "user"
age int // Non exporté - accessible uniquement dans le package "user"
}
Lorsqu’un autre package importe et utilise cette structure, il ne peut interagir qu’avec les champs exportés :
// Dans le package "main"
import "user"
func main() {
u := user.User{
Name: "Alice", // fonctionne
Email: "a@mail.com", // fonctionne
// password: "secret", // erreur de compilation : champ inconnu
}
fmt.Println(u.Name) // fonctionne
// fmt.Println(u.password) // erreur de compilation : impossible de faire référence à un champ non exporté
}
Ce mécanisme protège les données sensibles et les détails d’implémentation internes. Le champ password ne peut pas être lu ou modifié directement depuis l’extérieur du package, ce qui oblige les autres codes à utiliser les méthodes que vous fournissez. C’est l’approche de Go pour parvenir à la dissimulation des données : un principe fondamental de l’encapsulation dans la programmation orientée objet.
Défi
FacileConstruisons un système de compte bancaire qui démontre l'encapsulation à travers des champs exportés et non exportés. Vous allez créer un package qui protège les données financières sensibles tout en exposant des informations publiques sécurisées.
Vous organiserez votre code sur deux fichiers :
account.go: créez une structureBankAccountdans le packagemainqui modélise un véritable compte bancaire avec une protection appropriée des données :HolderName(exporté) - le nom du titulaire du compte, pouvant être affiché publiquement en toute sécuritéAccountType(exporté) - le type de compte (par ex. « Savings », « Checking »)balance(non exporté) - le solde réel, qui doit être protégépin(non exporté) - le code PIN du compte, une donnée hautement sensible
NewBankAccountqui prend le nom du titulaire, le type de compte, le solde initial et le PIN, puis renvoie un pointeur vers un nouveauBankAccount. Ajoutez également une méthodeGetPublicInfo() stringqui renvoie le format suivant :Account: [HolderName] ([AccountType])main.go: lisez les informations du compte depuis l'entrée, créez unBankAccountà l'aide du constructeur et démontrez l'encapsulation. Affichez les informations publiques à l'aide de la méthode, puis accédez directement à chaque champ exporté et affichez-les sur des lignes séparées. Les champs non exportés (balanceetpin) sont protégés. Vous ne pouvez les définir qu'à l'aide du constructeur.
Les entrées suivantes seront fournies :
- Ligne 1 : nom du titulaire du compte
- Ligne 2 : type de compte
- Ligne 3 : solde initial (sous forme de nombre flottant)
- Ligne 4 : code PIN
Par exemple, avec Alice Johnson, Savings, 5000.50 et 1234, votre sortie devrait être :
Account: Alice Johnson (Savings)
Holder: Alice Johnson
Type: SavingsRemarquez que le solde et le PIN n'apparaissent jamais dans la sortie : ils sont masqués en toute sécurité à l'intérieur de la structure, accessibles uniquement au sein du package. C'est l'encapsulation en action : les données sensibles sont protégées tandis que les informations publiques restent accessibles.
Essayez vous-même
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Lire le nom du titulaire du compte
holderName, _ := reader.ReadString('\n')
holderName = strings.TrimSpace(holderName)
// Lire le type de compte
accountType, _ := reader.ReadString('\n')
accountType = strings.TrimSpace(accountType)
// Lire le solde initial
balanceStr, _ := reader.ReadString('\n')
balanceStr = strings.TrimSpace(balanceStr)
balance, _ := strconv.ParseFloat(balanceStr, 64)
// Lire le PIN
pinStr, _ := reader.ReadString('\n')
pin := strings.TrimSpace(pinStr)
// TODO: Créer un nouveau BankAccount en utilisant le constructeur
// account := NewBankAccount(...)
// TODO: Afficher les infos publiques en utilisant la méthode GetPublicInfo()
// TODO: Afficher le nom du titulaire en accédant directement au champ exporté
// fmt.Println("Holder:", ...)
// TODO: Afficher le type de compte en accédant directement au champ exporté
// fmt.Println("Type:", ...)
// Note: balance et pin sont non exportés - ils ne peuvent pas être accédés directement ici
// Ils sont encapsulés en toute sécurité au sein de la struct
_ = balance // Supprimez cette ligne lorsque vous utilisez balance
_ = pin // Supprimez cette ligne lorsque vous utilisez pin
}
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