Menu
Coddy logo textTech

Profundidad en Getters y Setters

Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 33 de 110.

Los getters y setters se convierten en herramientas poderosas para la encapsulación cuando se combinan con campos privados. Permiten exponer una interfaz pública limpia mientras se mantiene el control total sobre cómo se accede y se modifican los datos.

Un patrón común es emparejar un campo privado con un getter público y un setter que incluya validación:

class Temperature {
  double _celsius = 0;
  
  double get celsius => _celsius;
  
  set celsius(double value) {
    if (value < -273.15) {
      _celsius = -273.15;  // Mínimo del cero absoluto
    } else {
      _celsius = value;
    }
  }
}

Los setters pueden aplicar reglas de negocio, asegurando que su objeto nunca entre en un estado no válido.

También puedes crear getters calculados que derivan valores a partir de datos privados:

class Rectangle {
  double _width;
  double _height;
  
  Rectangle(this._width, this._height);
  
  double get area => _width * _height;      // Computed
  double get perimeter => 2 * (_width + _height);
  
  double get width => _width;
  set width(double value) {
    if (value > 0) _width = value;
  }
}

A veces quieres acceso de solo lectura. Simplemente proporciona un getter sin un setter:

class Order {
  final DateTime _createdAt = DateTime.now();
  
  DateTime get createdAt => _createdAt;  // Solo lectura
}

Este patrón proporciona al código externo visibilidad de los datos mientras evita cualquier modificación: el campo privado combinado con solo un getter crea un verdadero acceso de solo lectura.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de inventario de productos que demuestre el poder de los getters y setters para controlar el acceso a los datos. Crearás una clase que proteja sus datos internos mientras proporciona propiedades calculadas y validación.

Organizarás tu código en dos archivos:

  • product.dart: Define una clase Product que gestione el inventario con una encapsulación adecuada. Tu producto debe tener:
    • Un String name público
    • Un double _price privado
    • Un int _quantity privado
    • Un constructor que reciba los tres valores
    • Un getter price que devuelva el precio privado
    • Un setter price que solo acepte valores mayores que 0 (ignora los valores inválidos)
    • Un getter quantity que devuelva la cantidad privada
    • Un setter quantity que solo acepte valores de 0 o mayores (ignora los valores negativos)
    • Un getter calculado totalValue que devuelva _price * _quantity
    • Un getter calculado isInStock que devuelva true si la cantidad es mayor que 0
    • Un getter de solo lectura sku que genere un SKU simple devolviendo los primeros 3 caracteres del nombre en mayúsculas seguidos de la cantidad (por ejemplo, LAP25 para "Laptop" con cantidad 25)
    • Un método displayProduct() que muestre los detalles del producto
  • main.dart: Importa tu clase de producto y demuestra cómo los getters y setters controlan el acceso:
    • Crea un producto llamado 'Laptop' con precio 999.99 y cantidad 25
    • Llama a displayProduct()
    • Imprime In stock: [isInStock]
    • Imprime SKU: [sku]
    • Intenta establecer el precio a -50.0 (debe ser ignorado)
    • Establece el precio a 899.99 (cambio válido)
    • Intenta establecer la cantidad a -10 (debe ser ignorado)
    • Establece la cantidad a 0 (cambio válido)
    • Llama a displayProduct()
    • Imprime In stock: [isInStock]
    • Imprime SKU: [sku]

El método displayProduct() debe imprimir en este formato:

--- Product Info ---
Name: [name]
Price: $[price]
Quantity: [quantity]
Total Value: $[totalValue]

Salida esperada:

--- Product Info ---
Name: Laptop
Price: $999.99
Quantity: 25
Total Value: $24999.75
In stock: true
SKU: LAP25
--- Product Info ---
Name: Laptop
Price: $899.99
Quantity: 0
Total Value: $0.0
In stock: false
SKU: LAP0

Hoja de referencia

Los getters y setters combinados con campos privados proporcionan encapsulación y control sobre el acceso a los datos.

Campo privado con Getter y Setter

class Temperature {
  double _celsius = 0;
  
  double get celsius => _celsius;
  
  set celsius(double value) {
    if (value < -273.15) {
      _celsius = -273.15;
    } else {
      _celsius = value;
    }
  }
}

Getters calculados

Los getters pueden derivar valores a partir de datos privados:

class Rectangle {
  double _width;
  double _height;
  
  Rectangle(this._width, this._height);
  
  double get area => _width * _height;
  double get perimeter => 2 * (_width + _height);
  
  double get width => _width;
  set width(double value) {
    if (value > 0) _width = value;
  }
}

Acceso de solo lectura

Proporcione un getter sin un setter para propiedades de solo lectura:

class Order {
  final DateTime _createdAt = DateTime.now();
  
  DateTime get createdAt => _createdAt;
}

Pruébalo tú mismo

import 'product.dart';

void main() {
  // TODO: Crear un producto llamado 'Laptop' con precio 999.99 y cantidad 25

  // TODO: Llamar a displayProduct()

  // TODO: Imprimir "In stock: [isInStock]"

  // TODO: Imprimir "SKU: [sku]"

  // TODO: Intentar establecer el precio a -50.0 (debe ser ignorado)

  // TODO: Establecer el precio a 899.99 (cambio válido)

  // TODO: Intentar establecer la cantidad a -10 (debe ser ignorado)

  // TODO: Establecer la cantidad a 0 (cambio válido)

  // TODO: Llamar a displayProduct()

  // TODO: Imprimir "In stock: [isInStock]"

  // TODO: Imprimir "SKU: [sku]"
}
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