¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Flutter
  3. Dart, conceptos avanzados
Extrait - Flutter Desarrolle sus aplicaciones móviles multiplataforma con Dart
Extractos del libro
Flutter Desarrolle sus aplicaciones móviles multiplataforma con Dart Volver a la página de compra del libro

Dart, conceptos avanzados

Introducción

Después de exponer las funciones básicas del lenguaje Dart, ahora es útil seguir descubriendo aspectos para estar perfectamente familiarizado con el tema. 

Los conceptos y nociones detallados en este capítulo son suficientes en el marco de este libro, cuyo objetivo es descubrir Flutter y sentirse lo suficientemente cómodos. Sin embargo, todavía hay mucho por descubrir sobre Dart. No es concebible describir todas las posibilidades de este lenguaje en dos capítulos. Debe entenderse que se trata de un lenguaje por derecho propio y que se podría dedicar a él todo un libro.

Sin embargo, nada nos impide descubrir los aspectos básicos (ya asimilados), a través de numerosos temas. El primero será las funciones. La palabra es deliberadamente generalista. Después se verá un gran aspecto del lenguaje a través de la programación orientada a objetos (POO). Aquí se estudiarán las clases y todos sus componentes. Sus interacciones (asociaciones, herencia, etc.) ayudarán a comprender mejor la utilidad de esta organización. También es el momento perfecto para entender cómo gestionar los errores que potencialmente pueden aparecer durante la ejecución de un programa (excepciones). Por último, se dará un vistazo al concepto de tratamiento asincrónico.

Funciones

1. Introducción

Ahora es el momento de abordar un primer concepto indispensable: se trata de las funciones. Van a permitir una separación precisa de código y la agrupación de funcionalidades. Hay varios tipos de funciones, partiendo de la función sencilla, pasando por la función con argumentos o la función con retorno e incluso la función anónima.

2. Función simple

Una función, en su forma más sencilla, no espera ningún argumento y no devuelve nada. Esta función es de tipo void. En la jerga informática, se denomina procedimiento. En el código que se ha presentado en el capítulo anterior, viene de la mano de un elemento crucial, main, el punto de entrada del programa. Como recordatorio, su sintaxis es la siguiente:

void main() { 
 //Punto de entrada del programa 
}  

Aquí hay otro ejemplo. Si el objetivo del programa es mostrar el tradicional «Hello World!», es posible conservar main y escribir una función que se llamará y cuyo papel será mostrar esa frase. Este puede ser el resultado:

void main() { 
//Punto de entrada del programa 
 mostrar(); 
}  
  
void mostrar() { 
 print("Hello World!"); 
} 

El programa anterior se ejecuta porque contiene un procedimiento main. La primera y única acción realizada es llamar a una función denominada mostrar(). Esta se escribe justo debajo. Es de tipo void, ya que no devuelve nada. Su único propósito es mostrar en la consola el contenido de la función de print(). El código está bien dividido y comienza a tener una estructura más ordenada.

3. Funciones con retorno

Una función con retorno se comporta globalmente de la misma manera que la función simple, excepto que se devolverá una respuesta.

Estas funciones se utilizan en un gran número de situaciones, como realizar un cálculo, verificar una condición, etc.

Las dos diferencias notables...

Programación orientada a objetos (POO)

1. Introducción

La programación orientada a objetos, comúnmente conocida como POO, es un paradigma de programación. La idea principal es asegurar que la representación que los seres humanos tenemos del mundo que nos rodea se pueda traducir a código informático. Para ello, es necesario representar una problemática a través de los actores, elementos u objetos en juego.

Si el propósito del software es administrar clientes y proveedores, la manera más sencilla es obtener una representación de cada uno en forma de código procesable. Para empezar, tendrá que crear clases que serán el molde de cada elemento. En el interior se describirán las características intrínsecas de cada objeto. A estos se le llaman atributos. Estos objetos también tendrán funcionalidades (métodos). A partir de entonces, podrán trabajar juntos, ya sea por medio de la herencia o de una asociación.

2. Clase

La clase se puede considerar como un molde que se utilizará para crear objetos llamados instancias. Para crear una clase, simplemente abra un nuevo archivo Dart. Una vez abierto, escriba la palabra clave class, luego asígnele un nombre y finalmente abra las llaves:

class Persona { 
 
} 

Se puede crear una clase en cualquier lugar. A continuación de una función main, por ejemplo. Entonces se trata de una clase interna. Como buena práctica, es aconsejable crear archivos independientes, que contenga cada uno solo una clase. Para utilizarlos en otro archivo, el que contiene el procedimiento main, por ejemplo, será necesario realizar un import:

import 'Persona.dart'; 
 
void main() { 
} 

3. Atributos

En una clase, los atributos se pueden considerar como las características del objeto. Una persona tiene un nombre, un apellido, una fecha de nacimiento, etc. Un coche tiene un color, una marca, un modelo, etc.

Dentro de la clase, el desafío será declarar estos atributos de la misma manera que cualquier variable. Tendrán un tipo y se nombrarán de manera explícita. Sin embargo, hay una característica especial que es preciso respetar: la encapsulación.

Se trata de proteger estos elementos del contacto externo para garantizar...

Generalidad

La generalidad se usa habitualmente para hacer el trabajo más conciso y versátil. Ofrece la posibilidad de que una clase que se apoya en otra en el marco de una asociación haga de modo que ya no se limite a esta, sino que pueda acomodar cualquier clase.

La generalidad ya se ha abordado sin saberlo durante el capítulo anterior, a través de las listas. Las listas pueden funcionar con todo tipo de objetos. La generalidad se reconoce por su sintaxis singular, donde el tipo esperado se escribe entre corchetes angulares.

List<int> listaDeNombres; 

Por supuesto, hay algunas clases genéricas que ya están presentes en el SDK, como las listas. Pero el principal interés es poder crear nuestras propias clases utilizando este efecto.

En el ejemplo que hemos seguido en este capítulo, se ha creado una clase de Direccion y se ha asociado a Persona. Sin embargo, en términos de los países de residencia, las direcciones varían. Si las personas que utilizan la aplicación son españolas o estadounidenses, deberá poder manejar ambos tipos de instrucciones. La diferencia se sitúa principalmente en el hecho de que en España se utiliza un código postal (de cinco caracteres), mientras que en Estado Unidos se utiliza un código ZIP (de cinco o nueve caracteres), añadiendo un estado.

Para empezar, debe modificar Direccion porque esta clase ya no se instanciará. Por lo tanto, se convertirá en abstract y luego servirá como la clase madre para dos nuevas clases: DireccionES y DireccionUS. El atributo codigoPostal también desaparecerá.

He aquí el código modificado de Direccion:

abstract class Direccion { 
 int _numeroDeVia; 
 String _nombreDeLaVia; 
 String _provincia; 
 
 Direccion(int numeroDeVia, String nombreDeLaVia, 
     String provincia) {  
   this._numeroDeVia = numeroDeVia;  
   this._nombreDeLaVia = nombreDeLaVia;  
   this._provincia...

Excepción

Las excepciones son errores. Pueden surgir en varios momentos durante la ejecución del programa, como en medio de un tratamiento de tipo algorítmico o como resultado de una acción del usuario. Indican que algo salió mal.

Se pueden clasificar en dos categorías:

  • Las llamadas excepciones de «sistema». La mayoría de las veces, se deben a una acción habitual y potencialmente peligrosa para la que se ha previsto una excepción muy específica.

  • Las demás están más relacionadas con problemas que nos planteamos, como las limitaciones del negocio. Se desencadenan voluntariamente cuando se produce una acción no conforme.

1. Excepciones de sistema

Las excepciones del sistema son habituales. Responden a los problemas más frecuentes. Dart incluye seis tipos principales de excepciones:

  • DefferredLoadException: se desencadena cuando una librería diferida no se carga.

  • FormatException: se desencadena cuando una cadena u otros datos no tienen el formato esperado y no se pueden convertir ni procesar.

  • IntegerDivisionByZeroException: se desencadena cuando se intenta una división por cero.

  • IOException: se genera cuando se produce un problema durante las operaciones de tipo IO (Input/Output).

  • IsolateSpawnException: se desencadena cuando isolate no se puede crear.

  • TimeOutException: se lanza cuando se alcanza un tiempo de espera programado, mientras se espera un resultado asincrónico.

Todas estas excepciones implementan la clase Exception, que es más genérica. También se debe tener en cuenta que existen otras excepciones aún más específicas. Estas implementan al menos una de las seis excepciones mencionadas anteriormente.

He aquí un ejemplo para poner esto en práctica. El siguiente código es incorrecto: 

void main() { 
 String nombre = null; 
 
 nombre.toUpperCase(); 
} 

No es posible aplicar toUpperCase() a un elemento que vale null; se corre el riego de obtener este mensaje:

Unhandled exception:

NoSuchMethodError: The method ’toUpperCase’ was called on null.

Receiver: null

Tried calling: toUpperCase()

#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)

#1      main (file:///E:/ProjetDart/ExceptionMain.dart:4:7)

#2      _startIsolate.<anonymous...

Tratamiento asíncrono

El asincronismo es la posibilidad de que una tarea se realice de manera paralela a otra en un marco de tiempo diferente. Por ejemplo, obtener información de una base de datos puede llevar mucho tiempo. En esta situación, debe evitar bloquear la aplicación a toda costa. El resto del programa debe seguir funcionando durante esta búsqueda. Por tanto, la solicitud de la base de datos será asincrónica.

Dart tiene dos palabras clave para el asincronismo: async y await.

Juntas, a menudo se asocian con la clase Future<T>. Esta clase se usa para representar que un cálculo o la recuperación de datos se ha realizado con éxito (o ha fallado), que estará disponible en algún momento en el futuro.

También hay otra clase, Stream, que le permite trabajar sobre este asunto. Esta noción se discutirá en el capítulo Los estados.

Para ilustrar los comentarios mencionados anteriormente, implementemos este código:

Future<void> main() async { 
 print("1- Llego el primero"); 
 print(await retorno1()); 
 print("5- Llego el último"); 
} 
 
Future<String> retorno1()  { 
 print("2- Debo llegar el segundo");  
 var retorno = Future.delayed(Duration(seconds: 5), () =>  
"3- Llego un poco...