
Clases abstractas y enumeraciones
Clases abstractas:
En Dart, una clase abstracta es una clase que no puede ser instanciada directamente, sino que se utiliza como una clase base para otras clases derivadas. Una clase abstracta puede contener métodos abstractos, que son métodos sin implementación, así como métodos concretos con implementación. Las clases que heredan de una clase abstracta deben proporcionar implementaciones para los métodos abstractos definidos en la clase base.
Para definir una clase abstracta en Dart, se utiliza la palabra clave abstract
antes de la palabra clave class
.
Ejemplo:
abstract class Animal {
void hacerSonido(); // Método abstracto sin implementación
void comer() {
print('El animal está comiendo.');
} // Método concreto con implementación
}
class Perro extends Animal {
@override
void hacerSonido() {
print('El perro ladra.');
}
}
void main() {
Perro miPerro = Perro();
miPerro.hacerSonido(); // Imprime "El perro ladra."
miPerro.comer(); // Imprime "El animal está comiendo."
}
En el ejemplo anterior, la clase Animal
es una clase abstracta con un método abstracto hacerSonido()
que no tiene implementación. La clase también tiene un método concreto comer()
que tiene una implementación.
La clase Perro
hereda de la clase Animal
y proporciona una implementación para el método abstracto hacerSonido()
utilizando la anotación @override
.
Las clases abstractas son útiles cuando se quiere definir una estructura común y métodos comunes para clases relacionadas, pero no se desea instanciar directamente la clase base. Se utilizan como una herramienta de abstracción para compartir comportamiento y definir una interfaz común para las clases derivadas.
Enumeraciones:
En Dart, las enumeraciones (enums) son una forma de representar un conjunto fijo de valores constantes. Una enumeración permite definir un tipo con un conjunto predefinido de valores que se pueden utilizar en el código. Cada valor en una enumeración se denomina miembro o constante de la enumeración.
Para definir una enumeración en Dart, se utiliza la palabra clave enum
.
Ejemplo:
enum DiaSemana {
lunes,
martes,
miércoles,
jueves,
viernes,
sábado,
domingo
}
void main() {
DiaSemana hoy = DiaSemana.miércoles;
print(hoy); // Imprime "DiaSemana.miércoles"
}
En el ejemplo anterior, se define una enumeración llamada DiaSemana
que representa los días de la semana. Los miembros de la enumeración son lunes
, martes
, miércoles
, jueves
, viernes
, sábado
y domingo
.
En la función main()
, se crea una variable hoy
de tipo DiaSemana
y se le asigna el valor DiaSemana.miércoles
. Luego, se imprime el valor de hoy
por consola.
Las enumeraciones son útiles cuando se desea representar un conjunto limitado y predefinido de valores en el código. Proporcionan una forma legible y mantenible de trabajar con valores constantes y ayudan a evitar errores al proporcionar un conjunto fijo de opciones válidas.
Extends
En Dart, las palabras clave extends
e implements
se utilizan para establecer relaciones de herencia y de implementación de interfaces entre clases.
La palabra clave extends
se utiliza para establecer una relación de herencia entre una clase (subclase) y otra clase (superclase). La subclase hereda los miembros (propiedades y métodos) de la superclase, lo que significa que puede acceder y utilizar esos miembros en la subclase. Ejemplo:
class Vehiculo {
void acelerar() {
print('El vehículo está acelerando.');
}
}
class Coche extends Vehiculo {
void frenar() {
print('El coche está frenando.');
}
}
void main() {
Coche miCoche = Coche();
miCoche.acelerar(); // Método heredado de la superclase
miCoche.frenar(); // Método propio de la subclase
}
En el ejemplo anterior, la clase Vehiculo
es la superclase y la clase Coche
es la subclase. La subclase Coche
utiliza la palabra clave extends
seguida del nombre de la superclase Vehiculo
para establecer la relación de herencia.
Como resultado, la subclase Coche
hereda el método acelerar()
de la superclase Vehiculo
y también puede definir sus propios métodos, como el método frenar()
.
Implements
La palabra clave implements
se utiliza para establecer una relación de implementación de interfaces. Una interfaz en Dart define una lista de métodos que una clase debe implementar. Una clase que implementa una interfaz debe proporcionar implementaciones para todos los métodos definidos en la interfaz. Ejemplo:
abstract class Animal {
void hacerSonido();
}
class Perro implements Animal {
@override
void hacerSonido() {
print('El perro ladra.');
}
}
void main() {
Perro miPerro = Perro();
miPerro.hacerSonido(); // Método implementado de la interfaz
}
En el ejemplo anterior, la clase Animal
es una interfaz que define un método hacerSonido()
. La clase Perro
utiliza la palabra clave implements
seguida del nombre de la interfaz Animal
para establecer la relación de implementación.
La clase Perro
debe proporcionar una implementación para el método hacerSonido()
definido en la interfaz Animal
, utilizando la anotación @override
para indicar que está sobrescribiendo el método.
Al implementar la interfaz, la clase Perro
debe proporcionar una implementación para el método hacerSonido()
, en este caso, el perro ladra.
Las palabras clave extends
e implements
son fundamentales para establecer relaciones de herencia y de implementación de interfaces en Dart. Permiten crear jerarquías de clases y garantizar que las clases derivadas hereden comportamientos o cumplan con los contratos de las interfaces definidas en Dart.
Ejercicio de la Sesión
void main(){
final windPlant = WindPlant( initialEnergy: 100);
final nuclearPlant = NuclearPlant( energyLeft: 1000 );
print( 'wind: ${ chargePhone(windPlant) }' );
print( 'nuclear: ${ chargePhone(nuclearPlant) }' );
}
double chargePhone( EnergyPlant plant ){
if( plant.energyLeft < 10 ){
throw Exception('Not enough energy');
}
return plant.energyLeft - 10;
}
enum PlantType { nuclear, wind, water }
abstract class EnergyPlant {
double energyLeft;
final PlantType type; //nuclear, wind, water
EnergyPlant({
required this. energyLeft,
required this.type
});
void consumeEnergy( double amount );
}
// extends o implements
class WindPlant extends EnergyPlant {
WindPlant({ required double initialEnergy })
: super( energyLeft: initialEnergy, type: PlantType.wind );
@override
void consumeEnergy( double amount ){
energyLeft -= amount;
}
}
class NuclearPlant implements EnergyPlant {
@override
double energyLeft;
@override
final PlantType type = PlantType.nuclear;
NuclearPlant({ required this.energyLeft });
@override
void consumeEnergy( double amount ){
energyLeft -= (amount * 0.5);
}
}