Interfaces en Dart
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 45 de 110.
A diferencia de muchos lenguajes que tienen una palabra clave interface dedicada, Dart adopta un enfoque diferente. En Dart, cada clase define automáticamente una interfaz. Esta interfaz consta de todos los miembros públicos (métodos y propiedades) que la clase declara.
Cuando quieres que una clase prometa que proporcionará cierta funcionalidad sin heredar la implementación, utilizas la palabra clave implements:
class Printer {
void printDocument(String content) {
print('Printing: $content');
}
}
class Scanner {
void scan() {
print('Scanning document');
}
}
// MultiFunctionDevice debe implementar TODOS los métodos de ambas clases
class MultiFunctionDevice implements Printer, Scanner {
@override
void printDocument(String content) {
print('MFD printing: $content');
}
@override
void scan() {
print('MFD scanning');
}
}La diferencia clave con respecto a extends es que implements no hereda ningún código. Debes proporcionar tu propia implementación para cada método y propiedad definidos en la interfaz. Este es un contrato: estás prometiendo que tu clase tendrá estas capacidades, pero tú decides exactamente cómo funcionan.
Este enfoque le da flexibilidad a Dart. Puedes usar clases abstractas cuando quieras definir interfaces sin implementación, o usar clases regulares como interfaces cuando tenga sentido. La siguiente lección explora cómo funciona este concepto de "interfaz implícita" con más detalle.
Desafío
FácilVamos a construir un sistema de reproductor de medios que demuestre cómo funciona la palabra clave implements en Dart. Crearás clases que sirvan como interfaces y luego las implementarás en un único dispositivo que combine múltiples capacidades.
Organizarás tu código en dos archivos:
media.dart: Define tus clases de interfaz y la clase implementadora aquí:- Una clase
AudioPlayercon un métodoplayAudio(String track)que imprimaPlaying audio: [track] - Una clase
VideoPlayercon un métodoplayVideo(String title)que imprimaPlaying video: [title] - Una clase
SmartTVque implemente tantoAudioPlayercomoVideoPlayer. Dado queimplementsno hereda ningún código, debes proporcionar tus propias implementaciones para ambos métodos. TuSmartTVdebe imprimirSmartTV audio: [track]para el audio ySmartTV video: [title]para el video
- Una clase
main.dart: Importa tu archivo de medios y demuestra cómo una sola clase puede implementar múltiples interfaces:- Crea una instancia de
SmartTV - Llama a
playAudio('Jazz Collection') - Llama a
playVideo('Nature Documentary')
- Crea una instancia de
Observa cómo SmartTV debe proporcionar su propia implementación para cada método de ambas interfaces; no hereda las implementaciones originales de AudioPlayer o VideoPlayer. Esta es la diferencia clave entre implements y extends.
Salida esperada:
SmartTV audio: Jazz Collection
SmartTV video: Nature DocumentaryHoja de referencia
En Dart, cada clase define automáticamente una interfaz que consiste en todos sus miembros públicos. Para implementar una interfaz sin heredar código, utiliza la palabra clave implements:
class Printer {
void printDocument(String content) {
print('Printing: $content');
}
}
class Scanner {
void scan() {
print('Scanning document');
}
}
// Debe implementar TODOS los métodos de ambas clases
class MultiFunctionDevice implements Printer, Scanner {
@override
void printDocument(String content) {
print('MFD printing: $content');
}
@override
void scan() {
print('MFD scanning');
}
}Diferencias clave con respecto a extends:
implementsno hereda ninguna implementación de código- Debes proporcionar tu propia implementación para cada método y propiedad
- Una clase puede implementar múltiples interfaces
- Es un contrato que promete que tu clase tendrá estas capacidades
Pruébalo tú mismo
import 'media.dart';
void main() {
// TODO: Crear una instancia de SmartTV
// TODO: Llamar a playAudio('Jazz Collection')
// TODO: Llamar a playVideo('Nature Documentary')
}
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