Menu
Coddy logo textTech

Incapsulamento a livello di package

Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 48 di 107.

Mentre la lezione precedente trattava la visibilità a livello di campo, l’incapsulamento di Go opera in realtà a livello di pacchetto. Tutto ciò che si trova nello stesso pacchetto, indipendentemente dal file in cui si trova, può accedere ai campi e alle funzioni non esportati.

Considera un pacchetto con più file:

// account/account.go
package account

type Account struct {
    balance int  // non esportato
}

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

func ResetAccount(a *Account) {
    a.balance = 0  // funziona - stesso package
}

Entrambi i file appartengono al pacchetto account, quindi helper.go può accedere direttamente al campo non esportato balance. È intenzionale. Ti permette di suddividere la logica del pacchetto tra più file mantenendo l'accesso interno.

Tuttavia, il codice esterno al pacchetto non può accedere ai membri non esportati:

// main.go
package main

import "account"

func main() {
    acc := &account.Account{}
    acc.Deposit(100)        // funziona - metodo esportato
    // acc.balance = 50     // errore - campo non esportato
    // account.ResetAccount // funzionerebbe se ResetAccount fosse esportato
}

Questo confine a livello di pacchetto è il principale meccanismo di incapsulamento di Go. Progetti i pacchetti come unità coese, in cui il codice interno collabora liberamente, mentre il codice esterno interagisce solo tramite l’API esportata. Considera ogni pacchetto come un modulo autonomo con un’interfaccia pubblica chiara.

challenge icon

Sfida

Facile

Costruiamo un sistema di gestione dell'inventario che mostra come più file all'interno dello stesso package possano collaborare accedendo direttamente ai campi non esportati, mantenendo al contempo quei dati nascosti al codice esterno.

Creerai tre file che lavorano insieme nel package main:

  • product.go: Definisci una struct Product con un campo esportato Name e un campo non esportato quantity (int). Aggiungi un metodo esportato Info() string che restituisce il formato: [Name]: [quantity] in stock
  • inventory.go: Crea funzioni di supporto che lavorano con i prodotti accedendo direttamente al campo non esportato quantity (possibile perché si trovano nello stesso package). Implementa:
    • Restock(p *Product, amount int) - aggiunge l'importo alla quantità del prodotto
    • Sell(p *Product, amount int) bool - sottrae l'importo dalla quantità se le scorte sono sufficienti; restituisce true in caso di successo o false se le scorte non sono sufficienti
    • NewProduct(name string, initialQty int) *Product - costruttore che crea un prodotto con il nome e la quantità iniziale specificati
  • main.go: Leggi i dettagli del prodotto dall'input, crea un prodotto usando il costruttore, esegui le operazioni sull'inventario e visualizza i risultati. Dopo ogni operazione, stampa le informazioni sul prodotto per mostrare lo stato aggiornato.

Verranno forniti i seguenti input:

  • Riga 1: Nome del prodotto
  • Riga 2: Quantità iniziale (intero)
  • Riga 3: Quantità da rifornire (intero)
  • Riga 4: Quantità da vendere (intero)

Dopo aver creato il prodotto, stampa le sue informazioni iniziali. Poi rifornisci le scorte e stampa di nuovo le informazioni. Infine, prova a vendere e stampa le informazioni aggiornate (se l'operazione riesce) oppure Sale failed: insufficient stock (se la quantità non è sufficiente).

Ad esempio, dati Laptop, 10, 5 e 8, l'output dovrebbe essere:

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

E dati Phone, 3, 2 e 10, l'output dovrebbe essere:

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

L'idea chiave è che inventory.go può leggere e modificare direttamente il campo non esportato quantity perché si trova nello stesso package di product.go. Questo è un esempio di incapsulamento a livello di package: la collaborazione interna avviene liberamente, mentre i dati rimangono protetti dai package esterni.

Provalo tu

package main

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

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

	// Leggi il nome del prodotto
	name, _ := reader.ReadString('\n')
	name = strings.TrimSpace(name)

	// Leggi la quantità iniziale
	initialQtyStr, _ := reader.ReadString('\n')
	initialQty, _ := strconv.Atoi(strings.TrimSpace(initialQtyStr))

	// Leggi la quantità da aggiungere alle scorte
	restockStr, _ := reader.ReadString('\n')
	restockAmount, _ := strconv.Atoi(strings.TrimSpace(restockStr))

	// Leggi la quantità da vendere
	sellStr, _ := reader.ReadString('\n')
	sellAmount, _ := strconv.Atoi(strings.TrimSpace(sellStr))

	// TODO: Crea un nuovo prodotto usando il costruttore NewProduct

	// TODO: Stampa le informazioni iniziali del prodotto

	// TODO: Rifornisci il prodotto e stampa le informazioni

	// TODO: Prova a vendere il prodotto e stampa il risultato
	// Se la vendita riesce, stampa le informazioni aggiornate
	// Se la vendita non riesce, stampa "Sale failed: insufficient stock"

	fmt.Println() // Sostituisci con l'output effettivo
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Go online