Métodos abstractos
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy. Lección 44 de 110.
Un método abstracto es un método declarado dentro de una clase abstracta que no tiene cuerpo. Define la firma del método pero deja la implementación a cada subclase. Cualquier clase que extienda la clase abstracta debe sobrescribir todos los métodos abstractos, o también será abstracta.
abstract class Animal {
// Método abstracto - sin cuerpo, debe ser implementado por las subclases
String makeSound();
// Método concreto - tiene un cuerpo, compartido por todas las subclases
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
@override
String makeSound() {
return 'Woof!'; // Debe proporcionar una implementación
}
}
class Cat extends Animal {
@override
String makeSound() {
return 'Meow!'; // Implementación diferente, misma firma
}
}Si una subclase olvida implementar un método abstracto, Dart te dará un error de compilación. Este es el punto principal: los métodos abstractos imponen un contrato. Se garantiza que cada subclase tenga ese método, por lo que puedes llamarlo de forma segura en cualquier instancia del tipo abstracto.
// Puedes usar el tipo abstracto como un tipo de variable
Animal a = Dog();
print(a.makeSound()); // ¡Guau!
Animal b = Cat();
print(b.makeSound()); // ¡Miau!Los métodos abstractos son diferentes de los métodos concretos en una clase abstracta. Los métodos concretos tienen un cuerpo y se heredan tal cual. Los métodos abstractos no tienen cuerpo y deben ser sobrescritos.
Puedes mezclar ambos en la misma clase abstracta para compartir cierto comportamiento mientras obligas a las subclases a definir el suyo propio para otros.
| Característica | Método abstracto | Método concreto |
|---|---|---|
| Tiene cuerpo | No | Sí |
| Debe sobrescribirse | Sí | No |
| Propósito | Imponer contrato | Compartir comportamiento |
| Dónde | Solo en clase abstracta | Cualquier clase |
Desafío
FácilVamos a construir una calculadora de formas que demuestre los métodos abstractos en acción. Definirás una clase abstracta con métodos abstractos que cada forma debe implementar de manera diferente, y luego usarás esas formas a través de una interfaz común.
Organizarás tu código en cuatro archivos:
shape.dart: Define una clase abstractaShapecon un campofinalcolor(String) y un constructor que lo inicialice. Declara dos métodos abstractos:double area()ydouble perimeter(). También añade un método concretodescribe()que imprimaA [color] shape with area: [area] and perimeter: [perimeter]. Debido a quearea()yperimeter()son abstractos, cada subclase proporcionará su propio cálculo, perodescribe()funciona para todas ellas sin ser sobrescrito.circle.dart: Crea una claseCircleque extienda deShape. Tiene un campofinalradius(double). Su constructor tomacoloryradiusy pasacolorasuper. Implementaarea()para que devuelva3.14 * radius * radiusyperimeter()para que devuelva2 * 3.14 * radius.rectangle.dart: Crea una claseRectangleque extienda deShape. Tiene camposfinalwidthyheight(ambos double). Su constructor tomacolor,widthyheighty pasacolorasuper. Implementaarea()para que devuelvawidth * heightyperimeter()para que devuelva2 * (width + height).main.dart: Importa todos los archivos. Crea unCirclecon color'red'y radio5.0, y unRectanglecon color'blue', ancho4.0y alto6.0. Llama adescribe()en cada forma. Luego crea unaList<Shape>que contenga ambas formas, recorre la lista e imprimeArea: [area]para cada forma.
Salida esperada:
A red shape with area: 78.5 and perimeter: 31.400000000000002
A blue shape with area: 24.0 and perimeter: 20.0
Area: 78.5
Area: 24.0Pruébalo tú mismo
import 'shape.dart';
import 'circle.dart';
import 'rectangle.dart';
void main() {
// TODO: Crea un Circle con color 'red' y radio 5.0
// TODO: Crea un Rectangle con color 'blue', ancho 4.0 y alto 6.0
// TODO: Llama a describe() en el círculo
// TODO: Llama a describe() en el rectángulo
// TODO: Crea una List<Shape> que contenga ambas formas
// TODO: Recorre la lista e imprime "Area: [area]" para cada forma
}
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 RepositoryPractica por tu cuenta: Compilador de Dart online