Menu
Coddy logo textTech

Encapsulamento em Nível de Pacote

Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy — lição 48 de 107.

Enquanto a lição anterior abordou a visibilidade ao nível de campo, o encapsulamento do Go na verdade opera no nível de pacote. Tudo dentro do mesmo pacote — independentemente do arquivo em que esteja — pode acessar campos e funções não exportados.

Considere um pacote com múltiplos arquivos:

// account/account.go
package account

type Account struct {
    balance int  // não exportado
}

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

func ResetAccount(a *Account) {
    a.balance = 0  // funciona - mesmo pacote
}

Ambos os arquivos pertencem ao pacote account, então o helper.go pode acessar diretamente o campo balance não exportado. Isso é intencional — permite que você divida a lógica do pacote entre arquivos enquanto mantém o acesso interno.

No entanto, o código fora do pacote não pode acessar membros não exportados:

// main.go
package main

import "account"

func main() {
    acc := &account.Account{}
    acc.Deposit(100)        // funciona - método exportado
    // acc.balance = 50     // erro - campo não exportado
    // account.ResetAccount // funcionaria se ResetAccount fosse exportado
}

Este limite de nível de pacote é o principal mecanismo de encapsulamento do Go. Você projeta pacotes como unidades coesas onde o código interno colabora livremente, enquanto o código externo interage apenas por meio da API exportada. Pense em cada pacote como um módulo independente com uma interface pública clara.

challenge icon

Desafio

Fácil

Vamos construir um sistema de gerenciamento de inventário que demonstra como múltiplos arquivos dentro do mesmo pacote podem colaborar acessando campos não exportados diretamente, enquanto mantêm esses dados ocultos de códigos externos.

Você criará três arquivos que trabalham juntos no pacote main:

  • product.go: Defina uma struct Product com um campo exportado Name e um campo não exportado quantity (int). Adicione um método exportado Info() string que retorna o formato: [Name]: [quantity] in stock
  • inventory.go: Crie funções auxiliares que trabalham com produtos acessando diretamente o campo não exportado quantity (possível porque estão no mesmo pacote). Implemente:
    • Restock(p *Product, amount int) - adiciona a quantidade ao estoque do produto
    • Sell(p *Product, amount int) bool - subtrai a quantidade do estoque se houver saldo suficiente, retorna true se for bem-sucedido ou false se não houver estoque suficiente
    • NewProduct(name string, initialQty int) *Product - construtor que cria um produto com o nome e a quantidade inicial fornecidos
  • main.go: Leia os detalhes do produto da entrada, crie um produto usando o construtor, realize operações de inventário e exiba os resultados. Após cada operação, imprima as informações do produto para mostrar o estado atualizado.

As seguintes entradas serão fornecidas:

  • Linha 1: Nome do produto
  • Linha 2: Quantidade inicial (inteiro)
  • Linha 3: Quantidade de reposição (inteiro)
  • Linha 4: Quantidade de venda (inteiro)

Após criar o produto, imprima suas informações iniciais. Em seguida, reponha o estoque e imprima as informações novamente. Por fim, tente vender e imprima as informações atualizadas (se for bem-sucedido) ou Sale failed: insufficient stock (se não houver quantidade suficiente).

Por exemplo, dados Laptop, 10, 5, e 8, sua saída deve ser:

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

E dados Phone, 3, 2, e 10, sua saída deve ser:

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

O ponto principal aqui é que o inventory.go pode ler e modificar diretamente o campo não exportado quantity porque ele está no mesmo pacote que o product.go. Isso é o encapsulamento em nível de pacote em ação — a colaboração interna acontece livremente enquanto os dados permanecem protegidos de pacotes externos.

Folha de consulta

O encapsulamento do Go opera no nível de pacote, não no nível de arquivo. Todos os arquivos dentro do mesmo pacote podem acessar campos e funções não exportados, independentemente de em qual arquivo eles foram definidos.

Acesso em Nível de Pacote

Membros não exportados são acessíveis em todos os arquivos do mesmo pacote:

// account/account.go
package account

type Account struct {
    balance int  // não exportado
}

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

func ResetAccount(a *Account) {
    a.balance = 0  // funciona - mesmo pacote
}

Restrições de Pacotes Externos

Código fora do pacote não pode acessar membros não exportados:

// main.go
package main

import "account"

func main() {
    acc := &account.Account{}
    acc.Deposit(100)        // funciona - método exportado
    // acc.balance = 50     // erro - campo não exportado
}

Este design permite que você divida a lógica do pacote em vários arquivos, mantendo o acesso interno, criando unidades coesas com interfaces públicas claras.

Experimente você mesmo

package main

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

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

	// Ler o nome do produto
	name, _ := reader.ReadString('\n')
	name = strings.TrimSpace(name)

	// Ler a quantidade inicial
	initialQtyStr, _ := reader.ReadString('\n')
	initialQty, _ := strconv.Atoi(strings.TrimSpace(initialQtyStr))

	// Ler a quantidade de reposição
	restockStr, _ := reader.ReadString('\n')
	restockAmount, _ := strconv.Atoi(strings.TrimSpace(restockStr))

	// Ler a quantidade de venda
	sellStr, _ := reader.ReadString('\n')
	sellAmount, _ := strconv.Atoi(strings.TrimSpace(sellStr))

	// TODO: Criar um novo produto usando o construtor `NewProduct`

	// TODO: Imprimir as informações iniciais do produto

	// TODO: Repor o produto e imprimir as informações

	// TODO: Tentar vender e imprimir o resultado
	// Se a venda for bem-sucedida, imprimir as informações atualizadas
	// Se a venda falhar, imprimir "Sale failed: insufficient stock"

	fmt.Println() // Substituir pela saída real
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos