Menu
Coddy logo textTech

Interfaces implícitas

Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 46 de 110.

Dado que cada clase de Dart define automáticamente una interfaz, puedes usar cualquier clase como una interfaz, incluso clases concretas con implementaciones completas. Esto es lo que llamamos una interfaz implícita.

Considera una clase con propiedades y métodos:

class Logger {
  String prefix = '[LOG]';
  
  void log(String message) {
    print('$prefix $message');
  }
  
  void clear() {
    print('Clearing logs...');
  }
}

Cuando otra clase implementa Logger, debe proporcionar su propia implementación para todo, incluyendo la propiedad prefix:

class FileLogger implements Logger {
  @override
  String prefix = '[FILE]';
  
  @override
  void log(String message) {
    print('$prefix Writing to file: $message');
  }
  
  @override
  void clear() {
    print('Deleting log file...');
  }
}

Esta es la idea clave: cuando usas implements, estás diciendo "mi clase tendrá la misma forma" - los mismos métodos y propiedades. No heredas ningún código, constructores o valores por defecto. Solo prometes cumplir con la estructura de la interfaz.

Esto hace que las interfaces implícitas sean potentes para crear componentes intercambiables. El código que espera un Logger puede funcionar con cualquier clase que implemente su interfaz, independientemente de cómo funcione esa implementación internamente.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de notificaciones que demuestre cómo las clases concretas pueden servir como interfaces implícitas. Crearás una clase de notificación base y luego la implementarás de una manera completamente diferente, demostrando que implements requiere que proporciones todos los miembros tú mismo.

Organizarás tu código en dos archivos:

  • notification.dart: Define tus clases de notificación aquí:
    • Una clase Notification con una propiedad String channel establecida en 'default', un método send(String message) que imprime [channel]: [message], y un método getStatus() que devuelve el string 'Notification ready'
    • Una clase EmailNotification que implementa Notification. Dado que estás usando implements, debes proporcionar tu propia propiedad channel (establécela en 'email'), tu propio método send() que imprime Sending email: [message], y tu propio método getStatus() que devuelve 'Email service active'
    • Una clase PushNotification que implementa Notification. Establece su channel en 'push', haz que send() imprima Push alert: [message], y haz que getStatus() devuelva 'Push service connected'
  • main.dart: Importa tu archivo de notificación y demuestra cómo diferentes clases pueden implementar la misma interfaz implícita con comportamientos completamente diferentes:
    • Crea una instancia de EmailNotification y una de PushNotification
    • Para cada notificación, imprime su estado usando getStatus(), luego llama a send() con el mensaje 'Hello World'
    • Imprime una línea vacía entre las dos notificaciones

Recuerda: cuando usas implements, no estás heredando ningún código de Notification. Solo estás prometiendo que tu clase tendrá la misma forma: las mismas propiedades y métodos. Cada clase implementadora proporciona su propia implementación completa.

Salida esperada:

Email service active
Sending email: Hello World

Push service connected
Push alert: Hello World

Hoja de referencia

En Dart, cada clase define automáticamente una interfaz implícita. Esto significa que puedes usar cualquier clase como una interfaz, incluso clases concretas con implementaciones completas.

Cuando una clase usa implements, debe proporcionar su propia implementación para todas las propiedades y métodos de la interfaz. No heredas ningún código, constructores o valores por defecto; solo prometes cumplir con la estructura de la interfaz.

Ejemplo de una clase concreta:

class Logger {
  String prefix = '[LOG]';
  
  void log(String message) {
    print('$prefix $message');
  }
  
  void clear() {
    print('Clearing logs...');
  }
}

Implementando la interfaz implícita:

class FileLogger implements Logger {
  @override
  String prefix = '[FILE]';
  
  @override
  void log(String message) {
    print('$prefix Writing to file: $message');
  }
  
  @override
  void clear() {
    print('Deleting log file...');
  }
}

Esto hace que las interfaces implícitas sean potentes para crear componentes intercambiables. El código que espera un Logger puede funcionar con cualquier clase que implemente su interfaz, independientemente de la implementación interna.

Pruébalo tú mismo

import 'notification.dart';

void main() {
  // TODO: Crear una instancia de EmailNotification
  
  // TODO: Imprimir el estado de la notificación por correo electrónico usando getStatus()
  
  // TODO: Enviar un mensaje 'Hello World' usando la notificación por correo electrónico
  
  // TODO: Imprimir una línea vacía
  
  // TODO: Crear una instancia de PushNotification
  
  // TODO: Imprimir el estado de la notificación push usando getStatus()
  
  // TODO: Enviar un mensaje 'Hello World' usando la notificación push
  
}
quiz iconPonte a prueba

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