DMarlon Studio

Lección 3 · 3 de 20

Getters, setters y miembros privados · Dart

Proteja el estado de sus clases en Dart con miembros privados (_), getters calculados y setters que validan, con una cuenta bancaria de ejemplo.

Dart · Getters, setters y miembros privados en DMarlon Studio: el código del ejemplo y su salida en la terminal

En Dart no existen las palabras private ni public: un nombre que empieza por guion bajo (_balanceCents, _history) es privado de la biblioteca, es decir, del archivo donde está. Desde otro archivo no se puede leer ni escribir; dentro del mismo archivo, sí. Por eso la privacidad se nota sobre todo cuando el proyecto crece en varios archivos y cada clase vive en el suyo.

Los getters (get) se leen como un campo, sin paréntesis, pero calculan su valor cada vez. balance devuelve el saldo con formato y history devuelve una copia no modificable con List.unmodifiable, de modo que nadie de fuera pueda cambiar la lista interna: el intento account.history.add('fake') lanza UnsupportedError, que el programa captura.

Un setter (set) se usa como una asignación, account.dailyLimit = 20000, pero ejecuta código: aquí comprueba que el límite no sea negativo y anota el cambio en el historial. Con -1 lanza ArgumentError y el valor anterior se conserva. Tener getter y setter con el mismo nombre hace que, visto desde fuera, dailyLimit parezca un campo normal.

En main aparece el operador de cascada ..: BankAccount('Lucia')..deposit(12000)..deposit(3550) llama a dos métodos sobre el mismo objeto y el resultado de toda la expresión es la cuenta, no lo que devuelva deposit. Es muy habitual para configurar un objeto recién creado.

Código · main.dart

class BankAccount {  final String owner;  // A leading _ makes a name private to this file (its library).  int _balanceCents = 0;  int _dailyLimit = 50000;  final List<String> _history = [];  BankAccount(this.owner);  // Getters read like fields but are computed on demand.  String get balance => '${(_balanceCents / 100).toStringAsFixed(2)} EUR';  List<String> get history => List.unmodifiable(_history);  int get dailyLimit => _dailyLimit;  // A setter looks like an assignment, but can validate.  set dailyLimit(int cents) {    if (cents < 0) throw ArgumentError('limit cannot be negative');    _dailyLimit = cents;    _history.add('limit $cents');  }  void deposit(int cents) {    _balanceCents += cents;    _history.add('deposit $cents');  }}void main() {  final account = BankAccount('Lucia')..deposit(12000)..deposit(3550);  account.dailyLimit = 20000; // calls the setter  print('${account.owner}: ${account.balance}, limit ${account.dailyLimit}');  try { account.dailyLimit = -1; } on ArgumentError catch (e) { print('Rejected: ${e.message}'); }  try { account.history.add('fake'); } on UnsupportedError { print('Read-only: ${account.history}'); }}

Salida · dart run main.dart

Lucia: 155.50 EUR, limit 20000
Rejected: limit cannot be negative
Read-only: [deposit 12000, deposit 3550, limit 20000]

Para recordar

  • _nombre es privado del archivo (la biblioteca), no de la clase.
  • Un getter se lee como un campo y se calcula al pedirlo.
  • Un setter se usa con = y permite validar el valor.
  • Devuelva copias no modificables de sus listas internas.
  • .. encadena llamadas sobre el mismo objeto.

Ejercicio

Añada un método withdraw(int cents) que lance StateError si la retirada supera el saldo o el límite diario, y pruebe a retirar 30000 céntimos.