Asincronía en métodos de clase
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 80 de 110.
Ahora que sabes cómo manejar la inicialización asíncrona con métodos de fábrica, veamos cómo hacer que los métodos de instancia regulares sean asíncronos. Esto es sencillo: simplemente añade async a cualquier método y haz que devuelva un Future.
class WeatherService {
String _location;
WeatherService(this._location);
Future<String> fetchTemperature() async {
await Future.delayed(Duration(seconds: 1));
return '22°C in $_location';
}
Future<void> updateLocation(String newLocation) async {
await Future.delayed(Duration(milliseconds: 500));
_location = newLocation;
print('Location updated to $_location');
}
}
Future<void> main() async {
var service = WeatherService('London');
var temp = await service.fetchTemperature();
print(temp);
await service.updateLocation('Paris');
}Los métodos asíncronos pueden acceder y modificar variables de instancia al igual que los métodos regulares. La diferencia clave es que quienes los llaman deben usar await para el resultado. Los métodos que devuelven Future<void> no devuelven un valor, pero aun así deben ser esperados si quieres asegurarte de que se completen antes de continuar.
También puedes combinar múltiples llamadas asíncronas dentro de un método, o llamar a otros métodos asíncronos de la misma clase:
Future<String> getFullReport() async {
var temp = await fetchTemperature();
var humidity = await fetchHumidity();
return '$temp, Humidity: $humidity';
}Este patrón es esencial para clases que interactúan con recursos externos: APIs, bases de datos o cualquier operación que tome tiempo.
Desafío
Fácil¡Vamos a construir un rastreador de cartera de acciones que gestione los precios de las acciones y calcule los valores de la cartera utilizando métodos asíncronos! Crearás una clase que simule la obtención de datos de acciones en tiempo real y combine múltiples operaciones asíncronas para generar informes.
Organizarás tu código en dos archivos:
portfolio.dart: Crea una claseStockPortfolioque rastree las acciones y sus cantidades. Tu clase debe tener:- Un
Map<String, int>privado llamado_holdingsque almacene los símbolos de las acciones y el número de acciones en propiedad - Un constructor que inicialice
_holdingscomo un mapa vacío - Un método
addStock(String symbol, int quantity)que añada o actualice una tenencia de acciones (no asíncrono) - Un método asíncrono
fetchPrice(String symbol)que devuelva unFuture<double>. Simula un retraso de 50 milisegundos, luego devuelve un precio calculado como: la longitud del símbolo multiplicada por 25.5 - Un método asíncrono
getStockValue(String symbol)que devuelva unFuture<double>. Este debe esperar afetchPricepara el símbolo, multiplicarlo por la cantidad poseída y devolver el valor total. Si el símbolo no está en las tenencias, devuelve 0.0 - Un método asíncrono
getTotalValue()que devuelva unFuture<double>. Este debe calcular el valor combinado de todas las tenencias esperando agetStockValuepara cada acción y sumando los resultados - Un método asíncrono
generateReport()que devuelva unFuture<String>. Este debe construir un informe que muestre el valor de cada acción y el total. Formatea cada línea como[symbol]: $[value](valor con 1 decimal), seguido de una línea finalTotal: $[totalValue](también con 1 decimal)
- Un
main.dart: Importa tu archivo de cartera y demuestra cómo los métodos asíncronos funcionan juntos dentro de una clase:- Crea una instancia de
StockPortfolio - Añade estas tenencias:
AAPLcon 10 acciones,GOOGLcon 5 acciones,MSFTcon 8 acciones - Imprime
Fetching portfolio data... - Espera e imprime el resultado de
generateReport()
- Crea una instancia de
¡Observa cómo generateReport() llama a otros métodos asíncronos dentro de la misma clase, y cómo cada método se basa en los demás. ¡Usa toStringAsFixed(1) para formatear los valores decimales!
Salida esperada:
Fetching portfolio data...
AAPL: $1020.0
GOOGL: $637.5
MSFT: $816.0
Total: $2473.5Hoja de referencia
Para hacer que los métodos de instancia sean asíncronos, agregue la palabra clave async y devuelva un Future:
class WeatherService {
String _location;
WeatherService(this._location);
Future<String> fetchTemperature() async {
await Future.delayed(Duration(seconds: 1));
return '22°C in $_location';
}
Future<void> updateLocation(String newLocation) async {
await Future.delayed(Duration(milliseconds: 500));
_location = newLocation;
print('Location updated to $_location');
}
}Los métodos asíncronos pueden acceder y modificar variables de instancia. Quienes los llaman deben usar await para obtener el resultado. Los métodos que devuelven Future<void> no devuelven un valor, pero aun así deben ser esperados con await para asegurar su finalización.
Los métodos asíncronos pueden llamar a otros métodos asíncronos dentro de la misma clase:
Future<String> getFullReport() async {
var temp = await fetchTemperature();
var humidity = await fetchHumidity();
return '$temp, Humidity: $humidity';
}Este patrón es esencial para las clases que interactúan con recursos externos como APIs o bases de datos.
Pruébalo tú mismo
import 'portfolio.dart';
void main() async {
// TODO: Crear una instancia de StockPortfolio
// TODO: Añadir participaciones:
// - AAPL con 10 acciones
// - GOOGL con 5 acciones
// - MSFT con 8 acciones
// TODO: Imprimir "Fetching portfolio data..."
// TODO: Esperar (await) e imprimir el resultado de generateReport()
}
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