Flutter DART Clases
Revisión del 09:19 10 jul 2021 de Angelfg (discusión | contribuciones) (→Librerías. Privado/Público)
Sumario
Introducción
- Como comenté anteriormente este curso está pensado para alumnos que ya tienen conocimientos previos en algún lenguaje de programación orientado a objetos.
- En esta sección se va a explicar las diferencias y características con respecto a otros lenguajes orientados a objetos en lo que se refiere al uso de clases y objetos,
- Podéis consultar como se implementan en Java en Fundamentos de POO en Java y en la ampliación de la POO.
- En Dart no es necesario realizar el new cuando instanciamos una clase.
- Esto se emplea mucho en Flutter ya que todo en él se base en crear widgets (Clases) y por tanto aparecería de forma continua new´s por todos lados.
- Sin embargo, si vamos a emplear clases creadas por nosotros, se recomienda hacer uso de new para diferenciarlo de la llamada a una función.
- Veamos un ejemplo, con conceptos de otros lenguajes de programación orientado a objetos como el empleo del método toString:
class Vehiculo{ int? anoCompra; // Necesitamos indicar que admite valores nulos, ya que al instanciar no le damos un valor por defecto String? matricula; String? marca; @override String toString() => 'El vehículo de la marca $marca con matrícula $matricula se compró en el año $anoCompra'; } void main() { final veh1 = new Vehiculo(); veh1.marca='Opel'; veh1.matricula='1234GHZ'; veh1.anoCompra = 2018; print(veh1); final veh2 = Vehiculo(); // No necesitamos new, pero se recomienda si son clases nuestras veh2.marca='Peugot'; veh2.matricula='6543HZZ'; veh2.anoCompra = 2020; print(veh2); }
Constructores
- Funcionan igual que en el lenguaje Java.
- Veamos un ejemplo de uso:
class Vehiculo{ int? anoCompra; // Necesitamos indicar que admite valores nulos, ya que al instanciar no le damos un valor por defecto String? matricula; String? marca; Vehiculo(int anoCompra, String matricula, String marca){ this.anoCompra = anoCompra; this.marca = marca; this.matricula = matricula; } @override String toString() => 'El vehículo de la marca $marca con matrícula $matricula se compró en el año $anoCompra'; } void main() { final veh1 = new Vehiculo(2018,'Opel','1234GHZ'); print(veh1); final veh2 = Vehiculo(2020,'Peugot','6543HZZ'); print(veh2); }
- Fijarse que un constructor no es más que un método y por tanto podemos emplear todo lo aprendido con los parámetros (opciones, posicionales,...)
- Ejercicio propuesto: Modifica el ejercicio anterior y haz con los parámetros puedan ser enviados en cualquier orden especificando el nombre del parámetro en la llamada. Haz que todos ellos sean obligatorios.
- En el ejemplo anterior vimos que al definir las propiedades de la clase, éstas deberían admitir valores nulos, ya que cuando instanciamos no les damos unos valores iniciales.
- Para solucionarlo.
class Vehiculo{ int anoCompra; String matricula; String marca; Vehiculo(this.anoCompra,this.marca, this.matricula); // Esto hace que automaticamente asigne los valores enviados a las propiedades y obliga a instanciar con los 3 parámetros. @override String toString() => 'El vehículo de la marca $marca con matrícula $matricula se compró en el año $anoCompra'; } void main() { final veh1 = new Vehiculo(2018,'Opel','1234GHZ'); print(veh1); final veh2 = Vehiculo(2020,'Peugot','6543HZZ'); print(veh2); }
- Si quisiéramos emplear el paso de parámetros empleando sus nombres, debemos de hacer uso de las { }, pero haciendo obligatorios el paso de datos con la palabra reservada required como ya vimos anteriormente.
class Vehiculo{ int anoCompra; String matricula; String marca; Vehiculo({ required this.anoCompra, required this.marca, required this.matricula }); @override String toString() => 'El vehículo de la marca $marca con matrícula $matricula se compró en el año $anoCompra'; } void main() { final veh1 = new Vehiculo(anoCompra: 2018 ,marca: 'Opel',matricula: '1234GHZ'); print(veh1); final veh2 = Vehiculo(anoCompra: 2020,marca: 'Peugot',matricula: '6543HZZ'); print(veh2); }
NOTAS IMPORTANTES:
- En DART los constructores no se heredan.
- Para llamar a un constructor que esté definido en una clase superior, debemos emplear la palabra clave super. Ejemplos de uso en este enlace.
Mútliples constructores. Constructores con nombre
- En DART no existe la sobrecarga de constructores y por tanto no podemos definir múltiples constructores en base a diferente tipo o número de parámetros.
- Para solucionarlo, DART permite crear múltiples constructores con diferentes nombres de la forma: nombre_clase.nombre_constructor(parámetros).
class Vehiculo{ int anoCompra; String matricula; String marca; Vehiculo({required this.anoCompra,required this.marca, required this.matricula}); Vehiculo.sinAnho({required this.marca, required this.matricula}) : anoCompra = 2000; Vehiculo.sinAnhoMarca({required this.matricula}) : anoCompra = 2000, marca='Opel'; @override String toString() => 'El vehículo de la marca $marca con matrícula $matricula se compró en el año $anoCompra'; } void main() { final veh1 = new Vehiculo(anoCompra: 2018,marca: 'Opel',matricula: '1234GHZ'); print(veh1); final veh2 = new Vehiculo.sinAnho(marca: 'Opel',matricula: '2234GHZ'); print(veh2); final veh3 = new Vehiculo.sinAnhoMarca(matricula: '3234GHZ'); print(veh3); }
- Nota importante: Fijarse que estoy haciendo uso de otro constructor en el que indico los valores que van a guardar los atributos de la clase Coche. Como no envío el año de compra ni la marca, tendría que indicar en la definición del atributo, que dichos atributos puede recibir valores nulos o que tienen un valor por defecto.
- Pero he empleado otra característica de DART que consiste en poner, después de la definición de los parámetros, dos puntos seguido de las variables que queremos inicializar. Este código se ejecuta antes del constructor. Es lo que se conoce como inicializadores.
- Más información: https://dart.dev/guides/language/language-tour#constructors
Empleando Mapas
- En esta sección voy a explicar como, teniendo como fuente de datos un mapa, crear un objeto.
- Debéis recordar lo que expliqué acerca de los valores nulos al emplear mapas.
- Debéis recordar el empleo de inicializadores visto anteriormente en esta sección.
- Partimos de un mapa que va a guardar la información de un Coche.
- Normalmente los datos que tengan como fuente de datos Internet vendrán en formato JSON:
class Vehiculo{ int anoCompra; String matricula; String marca; Vehiculo({ required this.anoCompra, required this.marca, required this.matricula }); Vehiculo.fromJson(Map<String,String>dato) : this.anoCompra = int.parse(dato['anoCompra']!), this.matricula = dato['matricula']!, this.marca = dato['marca']!; @override String toString() => 'El vehículo de la marca $marca con matrícula $matricula se compró en el año $anoCompra'; } void main() { final vehiculoJson = { 'anoCompra' : '2020', 'matricula' : '1234GHZ', 'marca' : 'Opel' }; Vehiculo veh1 = Vehiculo.fromJson(vehiculoJson); print(veh1); }
Herencia
- Más información: https://dart.dev/guides/language/language-tour#extending-a-class
- La palabra clave para indicar que una clase deriva de otra es extends y para referencia a un método o propiedad de la clase padre expleamos la palabra clave super.
- Veamos un ejemplo de uso:
class Personal { String nombreCompleto; Personal(this.nombreCompleto); } class Alumno extends Personal{ String numCarnet; Alumno({required this.numCarnet, required String nombreCompleto}) : super(nombreCompleto); @override String toString() => 'Alumna/o:$nombreCompleto con número de carnet:$numCarnet'; } class Profesor extends Personal{ String nrp; Profesor({required this.nrp, required String nombreCompleto}) : super(nombreCompleto); @override String toString() => 'Profesor/a:$nombreCompleto con número de registro personal:$nrp'; } void main(){ final alum1 = new Alumno(numCarnet: 'C1A',nombreCompleto: 'Juan Luis Rodriguez'); final prof1 = new Profesor(nrp: '1234534',nombreCompleto: 'Luisa Sanchez Dragó'); print(alum1); print(prof1); }
Librerías. Privado/Público
- En DART cada archivo .dart puede estar formado por múltiples clases y conformar una librería y podemos agrupar un conjunto de librerías y herramientas en forma de paquetes.
- Más información sobre librerías y paquetes: https://dart.dev/guides/libraries/create-library-packages
- Para poder hacer uso de las clases que se encuentran definiadas en una librería tenemos que hacer uso de la palabra clave import al principio del archivo.
- Este ejemplo será necesario realizar en el Android Studio:
- Supongamos que tenemos un archivo de nombre '4Centro.dart' con un conjunto de clases definidas:
class Personal { String nombreCompleto; Personal(this.nombreCompleto); } class Alumno extends Personal{ String numCarnet; Alumno({required this.numCarnet, required String nombreCompleto}) : super(nombreCompleto); @override String toString() => 'Alumna/o:$nombreCompleto con número de carnet:$numCarnet'; } class Profesor extends Personal{ String nrp; Profesor({required this.nrp, required String nombreCompleto}) : super(nombreCompleto); @override String toString() => 'Profesor/a:$nombreCompleto con número de registro personal:$nrp'; }
- Y ahora queremos hacer uso de estas clases desde otro archivo DART.
- Para ello empleamos la orden import:
import 'Centro.dart'; void main(){ final alum1 = new Alumno(numCarnet: 'C1A',nombreCompleto: 'Juan Luis Rodriguez'); final prof1 = new Profesor(nrp: '1234534',nombreCompleto: 'Luisa Sanchez Dragó'); print(alum1); print(prof1); }
- Relacionado con lo anterior, en DART no existen los modificadores de acceso public, private, protected como en otros lenguajes de programación orientada a objetos.
- Solamente tenemos la posibilidad de hacer que una propiedad, método o clase sea privada anteponiendo un guión bajo a su nombre.
- De esta forma, dicha clase, método o propiedad sólo será visible para todo lo que se encuentra dentro del archivo DART.
- Siguendo el ejemplo anterior, yo no quiero que se pueda instanciar un objeto de la clase Personal.
- Para ello puedo definir la clase Personal como privada de la forma (fijarse en los guiones bajos):
class _Personal { String nombreCompleto; _Personal(this.nombreCompleto); } class Alumno extends _Personal{ String numCarnet; Alumno({required this.numCarnet, required String nombreCompleto}) : super(nombreCompleto); @override String toString() => 'Alumna/o:$nombreCompleto con número de carnet:$numCarnet'; } class Profesor extends _Personal{ String nrp; Profesor({required this.nrp, required String nombreCompleto}) : super(nombreCompleto); @override String toString() => 'Profesor/a:$nombreCompleto con número de registro personal:$nrp'; }
- Ahora, desde el archivo DART donde hacemos uso de estas clases, ya no me estará permitido crear una instancia de la clase Personal:
- Y el mismo concepto podría ser aplicado tanto a métodos como a propiedades.
Getters y Setters
- Más información: https://dart.dev/guides/language/language-tour#getters-and-setters
- Los getters y setters son unos métodos especiales que se llaman sin emplear paréntesis y aparentan ser propiedades de una clase, ya que se llaman de la misma forma: objeto.método (pero sin paréntesis).
- Por lo tanto, a nivel de programación van a aparentar que estamos obteniendo o asignando un valor a una propiedad, pero realmente dicha propiedad no existe.
- Si empleamos el método para obtener información (es decir, el método tiene un return) se denomina getter.
- Si empleamos el método para asignar un valor a una propiedad que sí exista se denomina setter.
Enlace a la página principal de la UD2
Enlace a la página principal del curso
-- Ángel D. Fernández González -- (2021).