Menu
Coddy logo textTech

Polimorfismo via Interfaces

Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy — lição 58 de 110.

Na lição anterior, você viu o polimorfismo através da herança - usando um tipo de classe pai para trabalhar com objetos filhos. Mas o polimorfismo também funciona através de interfaces, e essa abordagem é frequentemente mais flexível.

Quando classes implementam a mesma interface, você pode tratá-las polimorficamente mesmo que elas não tenham relação de herança:

abstract class Printable {
  void printDetails();
}

class Invoice implements Printable {
  @override
  void printDetails() => print('Invoice #1234');
}

class Report implements Printable {
  @override
  void printDetails() => print('Monthly Report');
}

class Receipt implements Printable {
  @override
  void printDetails() => print('Receipt for purchase');
}

void printAll(List<Printable> items) {
  for (var item in items) {
    item.printDetails();
  }
}

void main() {
  var documents = [Invoice(), Report(), Receipt()];
  printAll(documents);
}

Invoice, Report e Receipt são classes completamente não relacionadas - elas não compartilham um pai. No entanto, como todas implementam Printable, podemos armazená-las na mesma lista e chamar printDetails() em cada uma delas.

Isso é poderoso porque permite definir contratos de comportamento sem forçar uma hierarquia de herança. Qualquer classe pode implementar uma interface, independentemente do que ela estende. Seu código se torna mais modular, pois você pode adicionar novos tipos imprimíveis sem modificar o código existente - basta implementar a interface.

challenge icon

Desafio

Fácil

Vamos construir um sistema de player de mídia que demonstra polimorfismo através de interfaces. Você criará uma interface que define o que significa ser "reproduzível" (playable), e então implementará vários tipos de mídia não relacionados que cumprem esse contrato - permitindo que sejam manipulados de forma uniforme, apesar de não terem relação de herança.

Você organizará seu código em dois arquivos:

  • media.dart: Defina sua interface e classes de mídia aqui:
    • Uma classe abstrata Playable com dois métodos abstratos: play() e String getMediaType()
    • Uma classe Song que implementa Playable. Ela deve ter um String title e String artist. Seu método play() imprime Playing song: [title] by [artist] e getMediaType() retorna 'Audio'
    • Uma classe Video que implementa Playable. Ela deve ter um String title e int duration (em minutos). Seu método play() imprime Playing video: [title] ([duration] min) e getMediaType() retorna 'Video'
    • Uma classe Podcast que implementa Playable. Ela deve ter um String title e int episode. Seu método play() imprime Playing podcast: [title] - Episode [episode] e getMediaType() retorna 'Podcast'
    Também crie uma função playAll(List<Playable> playlist) que itera pela lista e, para cada item, imprime [Media Type]: seguido pela chamada de play() naquele item.
  • main.dart: Importe seu arquivo de mídia e demonstre o polimorfismo baseado em interface:
    • Crie uma List<Playable> contendo uma Song com o título 'Imagine' e o artista 'John Lennon', um Video com o título 'Dart Tutorial' e duração 15, e um Podcast com o título 'Tech Talk' e episódio 42
    • Passe esta lista para playAll()

Observe como Song, Video e Podcast não compartilham nenhuma classe pai - eles são tipos completamente não relacionados. No entanto, como todos implementam Playable, você pode armazená-los na mesma lista e tratá-los uniformemente através da interface.

Saída esperada:

Audio:
Playing song: Imagine by John Lennon
Video:
Playing video: Dart Tutorial (15 min)
Podcast:
Playing podcast: Tech Talk - Episode 42

Folha de consulta

O polimorfismo funciona por meio de interfaces, permitindo que classes não relacionadas sejam tratadas de forma uniforme sem relações de herança.

Classes que implementam a mesma interface podem ser usadas de forma polimórfica:

abstract class Printable {
  void printDetails();
}

class Invoice implements Printable {
  @override
  void printDetails() => print('Invoice #1234');
}

class Report implements Printable {
  @override
  void printDetails() => print('Monthly Report');
}

void printAll(List<Printable> items) {
  for (var item in items) {
    item.printDetails();
  }
}

void main() {
  var documents = [Invoice(), Report()];
  printAll(documents);
}

O polimorfismo baseado em interface permite que você:

  • Defina contratos de comportamento sem forçar hierarquias de herança
  • Armazene tipos não relacionados na mesma coleção
  • Adicione novos tipos sem modificar o código existente
  • Torne o código mais modular e flexível

Experimente você mesmo

import 'media.dart';

void main() {
  // TODO: Crie uma List<Playable> contendo:
  // - Uma Song com o título 'Imagine' e o artista 'John Lennon'
  // - Um Video com o título 'Dart Tutorial' e duração 15
  // - Um Podcast com o título 'Tech Talk' e episódio 42
  
  // TODO: Passe a lista para playAll()
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos