Campos Final y Const
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 18 de 110.
Al declarar campos en una clase, puedes usar final o const para controlar si los valores pueden cambiar después de la inicialización. Ambos crean valores inmutables, pero funcionan de manera diferente.
Un campo final solo se puede establecer una vez, pero su valor se determina en tiempo de ejecución. Puedes asignarlo en la declaración o a través de un constructor:
class Person {
final String name;
final DateTime createdAt = DateTime.now();
Person(this.name);
}
Person p = Person('Alice');
// p.name = 'Bob'; // Error: no se puede reasignar un campo finalEl name se establece cuando se crea el objeto, y createdAt captura la hora actual. Ambos valores se bloquean después de la inicialización.
Un campo static const debe tener un valor conocido en tiempo de compilación. Pertenece a la clase misma y se comparte entre todas las instancias:
class Circle {
static const double pi = 3.14159;
final double radius;
Circle(this.radius);
double get area => Circle.pi * radius * radius;
}La diferencia clave: los campos final pueden contener valores calculados en tiempo de ejecución (como DateTime.now()), mientras que const requiere constantes en tiempo de compilación. Los campos de instancia no pueden ser const directamente; solo se permite static const a nivel de clase.
Desafío
FácilVamos a construir un sistema de catálogo de productos que demuestre la diferencia entre los campos final y static const. Crearás productos con propiedades inmutables y valores de configuración compartidos.
Organizarás tu código en dos archivos:
product.dart: Define una claseProductque represente un artículo en una tienda. Tu clase debe tener:- Un
static const double taxRateestablecido en0.08(tasa de impuesto del 8% compartida por todos los productos) - Un
static const String currencyestablecido en'USD' - Un
final String namepara el nombre del producto (establecido a través del constructor) - Un
final double basePricepara el precio base del producto (establecido a través del constructor) - Un
final String sku(unidad de mantenimiento de existencias) que combine un prefijo con el nombre del producto, calculado en una lista de inicialización como'SKU-'seguido del nombre en mayúsculas - Un constructor que reciba
nameybasePrice - Un getter
priceWithTaxque calcule el precio incluyendo el impuesto - Un método
display()que imprima la información del producto
- Un
main.dart: Importa tu clase de producto y crea dos productos:- Un
'Laptop'con precio base999.99 - Un
'Mouse'con precio base29.99
display()en cada producto en el orden indicado anteriormente.- Un
El método display() debe imprimir exactamente en este formato:
[sku] - [name]: [basePrice] [currency] (with tax: [priceWithTax] [currency])Redondea priceWithTax a 2 decimales usando toStringAsFixed(2) al mostrarlo.
Salida esperada:
SKU-LAPTOP - Laptop: 999.99 USD (with tax: 1079.99 USD)
SKU-MOUSE - Mouse: 29.99 USD (with tax: 32.39 USD)Hoja de referencia
Usa final para campos que se establecen una vez en tiempo de ejecución y no pueden cambiarse después. Usa static const para constantes en tiempo de compilación compartidas entre todas las instancias de una clase.
Los campos final se establecen en tiempo de ejecución y pueden inicializarse en la declaración o en el constructor:
class Person {
final String name;
final DateTime createdAt = DateTime.now();
Person(this.name);
}Los campos static const deben tener valores constantes en tiempo de compilación y pertenecen a la propia clase:
class Circle {
static const double pi = 3.14159;
final double radius;
Circle(this.radius);
double get area => Circle.pi * radius * radius;
}Puedes calcular los valores de los campos final en una lista de inicializadores:
class Product {
final String name;
final String sku;
Product(this.name) : sku = 'SKU-${name.toUpperCase()}';
}Diferencias clave:
final: Valores en tiempo de ejecución, pueden ser diferentes para cada instanciastatic const: Constantes en tiempo de compilación, compartidas entre todas las instancias- Los campos de instancia no pueden ser
constdirectamente; solo se permitestatic const
Pruébalo tú mismo
import 'product.dart';
void main() {
// TODO: Crea un Product llamado 'Laptop' con un precio base de 999.99
// TODO: Crea un Product llamado 'Mouse' con un precio base de 29.99
// TODO: Llama a display() en cada producto en orden (Laptop primero, luego Mouse)
}
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