Menu
Coddy logo textTech

Encapsulation au niveau du package

Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy. Leçon 48 sur 107.

Bien que la leçon précédente ait traité de la visibilité au niveau des champs, l’encapsulation de Go s’effectue en réalité au niveau du package. Tout ce qui se trouve dans le même package, quel que soit le fichier dans lequel il se trouve, peut accéder aux champs et aux fonctions non exportés.

Considérez un package comportant plusieurs fichiers :

// account/account.go
package account

type Account struct {
    balance int  // non exporté
}

func (a *Account) Deposit(amount int) {
    a.balance += amount
}
// account/helper.go
package account

func ResetAccount(a *Account) {
    a.balance = 0  // fonctionne - même package
}

Les deux fichiers appartiennent au package account, donc helper.go peut accéder directement au champ non exporté balance. C’est intentionnel. Cela vous permet de répartir la logique du package entre plusieurs fichiers tout en conservant l’accès interne.

Cependant, le code situé en dehors du package ne peut pas accéder aux membres non exportés :

// main.go
package main

import "account"

func main() {
    acc := &account.Account{}
    acc.Deposit(100)        // fonctionne - méthode exportée
    // acc.balance = 50     // erreur - champ non exporté
    // account.ResetAccount // fonctionne si ResetAccount était exporté
}

Cette limite au niveau du package est le principal mécanisme d’encapsulation de Go. Vous concevez les packages comme des unités cohérentes où le code interne collabore librement, tandis que le code externe interagit uniquement avec l’API exportée. Considérez chaque package comme un module autonome doté d’une interface publique claire.

challenge icon

Défi

Facile

Construisons un système de gestion des stocks qui montre comment plusieurs fichiers d'un même package peuvent collaborer en accédant directement à des champs non exportés, tout en gardant ces données masquées pour le code externe.

Tu vas créer trois fichiers qui fonctionnent ensemble dans le package main :

  • product.go : définir une structure Product avec un champ Name exporté et un champ quantity non exporté (de type int). Ajouter une méthode Info() string exportée qui renvoie le format suivant : [Name]: [quantity] in stock
  • inventory.go : créer des fonctions utilitaires qui travaillent avec les produits en accédant directement au champ quantity non exporté (ce qui est possible parce qu'elles se trouvent dans le même package). Implémenter :
    • Restock(p *Product, amount int) - ajoute la quantité au stock du produit
    • Sell(p *Product, amount int) bool - soustrait la quantité du stock si celui-ci est suffisant, et renvoie true en cas de réussite ou false si le stock est insuffisant
    • NewProduct(name string, initialQty int) *Product - constructeur qui crée un produit avec le nom et la quantité initiale fournis
  • main.go : lire les informations du produit depuis l'entrée, créer un produit à l'aide du constructeur, effectuer les opérations de gestion des stocks et afficher les résultats. Après chaque opération, afficher les informations du produit pour montrer son état mis à jour.

Les entrées suivantes seront fournies :

  • Ligne 1 : nom du produit
  • Ligne 2 : quantité initiale (entier)
  • Ligne 3 : quantité réapprovisionnée (entier)
  • Ligne 4 : quantité vendue (entier)

Après avoir créé le produit, afficher ses informations initiales. Réapprovisionner ensuite le stock et afficher à nouveau les informations. Enfin, tenter de vendre le produit et afficher soit les informations mises à jour (en cas de réussite), soit Sale failed: insufficient stock (si la quantité en stock est insuffisante).

Par exemple, avec Laptop, 10, 5 et 8, la sortie doit être :

Laptop: 10 in stock
Laptop: 15 in stock
Laptop: 7 in stock

Et avec Phone, 3, 2 et 10, la sortie doit être :

Phone: 3 in stock
Phone: 5 in stock
Sale failed: insufficient stock

L'idée essentielle est que inventory.go peut lire et modifier directement le champ quantity non exporté parce qu'il se trouve dans le même package que product.go. Il s'agit ici d'un exemple d'encapsulation au niveau du package : la collaboration interne s'effectue librement, tandis que les données restent protégées des packages externes.

Essayez vous-même

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Lire le nom du produit
	name, _ := reader.ReadString('\n')
	name = strings.TrimSpace(name)

	// Lire la quantité initiale
	initialQtyStr, _ := reader.ReadString('\n')
	initialQty, _ := strconv.Atoi(strings.TrimSpace(initialQtyStr))

	// Lire la quantité de réapprovisionnement
	restockStr, _ := reader.ReadString('\n')
	restockAmount, _ := strconv.Atoi(strings.TrimSpace(restockStr))

	// Lire la quantité à vendre
	sellStr, _ := reader.ReadString('\n')
	sellAmount, _ := strconv.Atoi(strings.TrimSpace(sellStr))

	// TODO: Créer un nouveau produit en utilisant le constructeur NewProduct

	// TODO: Afficher les informations initiales du produit

	// TODO: Réapprovisionner le produit et afficher les informations

	// TODO: Tenter de vendre et afficher le résultat
	// Si la vente réussit, afficher les informations mises à jour
	// If sale fails, print "Sale failed: insufficient stock"

	fmt.Println() // Remplacer par la sortie réelle
}
quiz iconTestez-vous

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

Entraînez-vous par vous-même : Compilateur Go en ligne