Menu
Coddy logo textTech

Encapsulamiento a nivel de paquete

Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 48 de 107.

Aunque la lección anterior abordó la visibilidad a nivel de campo, la encapsulación de Go en realidad funciona a nivel de paquete. Todo lo que se encuentra dentro del mismo paquete, independientemente del archivo en el que esté, puede acceder a campos y funciones no exportados.

Considera un paquete con varios archivos:

// account/account.go
package account

type Account struct {
    balance int  // no exportado
}

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

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

Ambos archivos pertenecen al paquete account, por lo que helper.go puede acceder directamente al campo no exportado balance. Esto es intencional. Te permite dividir la lógica del paquete entre varios archivos manteniendo el acceso interno.

Sin embargo, el código fuera del paquete no puede acceder a miembros no exportados:

// main.go
package main

import "account"

func main() {
    acc := &account.Account{}
    acc.Deposit(100)        // funciona - método exportado
    // acc.balance = 50     // error - campo no exportado
    // account.ResetAccount // funciona si ResetAccount estuviera exportado
}

Este límite a nivel de paquete es el principal mecanismo de encapsulación de Go. Diseñas los paquetes como unidades cohesivas en las que el código interno colabora libremente, mientras que el código externo interactúa únicamente mediante la API exportada. Piensa en cada paquete como un módulo independiente con una interfaz pública clara.

challenge icon

Desafío

Fácil

Construyamos un sistema de gestión de inventory que demuestre cómo varios archivos dentro del mismo paquete pueden colaborar accediendo directamente a fields no Exported, mientras mantienen esos datos ocultos para el código externo.

Crearás tres archivos que trabajan juntos en el paquete main:

  • product.go: Define una estructura Product con un field Name Exported y un field quantity no Exported (int). Añade un method Info() string Exported que devuelva el format: [Name]: [quantity] in stock
  • inventory.go: Crea functions helper que trabajen con products accediendo directly al field no Exported quantity (es posible porque están en el mismo paquete). Implementa:
    • Restock(p *Product, amount int) - añade el amount a la cantidad del producto
    • Sell(p *Product, amount int) bool - resta el amount de quantity si hay suficiente stock, y devuelve true si tiene éxito o false si no hay enough stock
    • NewProduct(name string, initialQty int) *Product - constructor que creates un producto con el nombre y la cantidad initial dados
  • main.go: Lee los detalles del producto desde la entrada, crea un producto usando el constructor, realiza operaciones de inventory y muestra los resultados. Después de cada operación, imprime la información del producto para mostrar el estado actualizado.

Se proporcionarán las siguientes entradas:

  • Línea 1: Nombre del producto
  • Línea 2: Cantidad initial (entero)
  • Línea 3: Cantidad de reabastecimiento (entero)
  • Línea 4: Cantidad de venta (entero)

Después de crear el producto, imprime su información initial. Después, reabastécelo e imprime la información de nuevo. Finalmente, intenta vender y muestra la información actualizada (si tiene éxito) o Sale failed: insufficient stock (si no hay suficiente cantidad).

Por ejemplo, dados Laptop, 10, 5 y 8, tu salida debería ser:

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

Y dados Phone, 3, 2 y 10, tu salida debería ser:

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

La idea clave aquí es que inventory.go puede leer y modificar directly el field no Exported quantity porque está en el mismo paquete que product.go. Esta es la encapsulación a nivel de paquete en acción: la colaboración interna ocurre libremente, mientras los datos permanecen protegidos frente a otros paquetes.

Pruébalo tú mismo

package main

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

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

	// Leer el nombre del producto
	name, _ := reader.ReadString('\n')
	name = strings.TrimSpace(name)

	// Leer la cantidad inicial
	initialQtyStr, _ := reader.ReadString('\n')
	initialQty, _ := strconv.Atoi(strings.TrimSpace(initialQtyStr))

	// Leer la cantidad de reposición
	restockStr, _ := reader.ReadString('\n')
	restockAmount, _ := strconv.Atoi(strings.TrimSpace(restockStr))

	// Leer la cantidad a vender
	sellStr, _ := reader.ReadString('\n')
	sellAmount, _ := strconv.Atoi(strings.TrimSpace(sellStr))

	// TODO: Crear un nuevo producto usando el constructor NewProduct

	// TODO: Imprimir la información inicial del producto

	// TODO: Reponer el producto e imprimir la información

	// TODO: Intentar vender e imprimir el resultado
	// Si la venta tiene éxito, imprimir la información actualizada
	// If sale fails, print "Sale failed: insufficient stock"

	fmt.Println() // Reemplazar con la salida real
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Go online