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.
Desafío
FácilVamos 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 claseProductque gestione el inventario con una encapsulación adecuada. Tu producto debe tener:- Un
String namepúblico - Un
double _priceprivado - Un
int _quantityprivado - Un constructor que reciba los tres valores
- Un getter
priceque devuelva el precio privado - Un setter
priceque solo acepte valores mayores que0(ignora los valores inválidos) - Un getter
quantityque devuelva la cantidad privada - Un setter
quantityque solo acepte valores de0o mayores (ignora los valores negativos) - Un getter calculado
totalValueque devuelva_price * _quantity - Un getter calculado
isInStockque devuelvatruesi la cantidad es mayor que0 - Un getter de solo lectura
skuque genere un SKU simple devolviendo los primeros 3 caracteres del nombre en mayúsculas seguidos de la cantidad (por ejemplo,LAP25para "Laptop" con cantidad 25) - Un método
displayProduct()que muestre los detalles del producto
- Un
main.dart: Importa tu clase de producto y demuestra cómo los getters y setters controlan el acceso:- Crea un producto llamado
'Laptop'con precio999.99y cantidad25 - 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]
- Crea un producto llamado
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: LAP0Hoja 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]"
}
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
1Fundamentos de POO
Archivos externosLibrerías e importacionesIntroducción a la POOClases vs. ObjetosLa palabra clave thisMétodosVariables de instanciaConceptos básicos de constructoresResumen - Calculadora sencilla4Seguridad de nulos
Introducción a la seguridad de nulosNulables vs No nulablesLos operadores ? y !Palabra clave Late y Null SafetyOperadores Null-awareNull Safety en clasesResumen - Sistema de perfil de usuario7Clases abstractas e interfaces
Clases abstractasMétodos abstractosInterfaces en DartInterfaces implícitasImplementar vs. ExtenderInterfaces múltiplesRepaso - Calculadora de figuras10Colecciones y Genéricos
Visión general de List, Set y MapColecciones con seguridad de tiposClases genéricasMétodos genéricosRestricciones genéricasIterable e IteratorResumen - Almacenamiento genérico2Constructores en Dart
Constructor por defectoConstructores nombradosListas de inicializaciónConstructores constantesConstructores de fábricaConstructores de redireccionamientoResumen - Constructor de formas5Encapsulamiento
Miembros públicos vs. privadosLa convención del prefijo _Privacidad a nivel de libreríaProfundidad en Getters y SettersOcultamiento de informaciónResumen - Registros de estudiantes8Mixins
Introducción a los MixinsCreación de MixinsUso de múltiples MixinsPalabra clave on en MixinsMixin vs HerenciaMixin vs InterfazResumen - Sistema Animal11Métodos especiales
Sobrescritura de toString()Sobrescritura de hashCode y ==Interfaz ComparableMétodo call()Sobrescritura de noSuchMethodResumen - Colección personalizada14Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy3Propiedades de clase
Miembros de instancia vs. estáticosCampos Final y ConstVariables LateMétodos y campos estáticosGetters y SettersResumen - Gestor de cuentas bancarias6Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosLa anotación @overrideLa palabra clave final en clasesConstructores y herenciaResumen - Jerarquía de empleados9Polimorfismo
Fundamentos del polimorfismoPolimorfismo mediante interfacesComprobación de tipos en tiempo de ejecuciónLos operadores is y asPalabra clave covariantResumen - Procesador de pagos12POO Asíncrona
Futures y async/awaitFundamentos de StreamsStream ControllersConstructores asíncronosAsincronía en métodos de claseRepaso - Data Fetcher15Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository