Menu
Coddy logo textTech

Implementando vs Estendendo

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

Agora que você entende tanto o extends quanto o implements, vamos esclarecer quando usar cada um.

Use extends quando você quiser herdar comportamento. Sua subclasse recebe todo o código do pai gratuitamente e pode construir sobre ele:

class Animal {
  void breathe() {
    print('Breathing...');
  }
}

class Dog extends Animal {
  void bark() {
    print('Woof!');
  }
}

void main() {
  var dog = Dog();
  dog.breathe();  // Herdado - funciona automaticamente
  dog.bark();
}

Use implements quando você deseja garantir uma estrutura sem herdar código. Você deve escrever cada método por conta própria:

class Robot implements Animal {
  @override
  void breathe() {
    print('Ventilating circuits...');  // Implementação completamente personalizada
  }
}

A principal diferença: extends diz "Eu sou um tipo disso" enquanto implements diz "Eu posso fazer o que isso faz." Um Dog é um Animal e respira da mesma forma. Um Robot não é um animal, mas pode cumprir o mesmo contrato com sua própria lógica.

Lembre-se: você só pode estender uma classe, mas pode implementar muitas interfaces. Escolha extends para relacionamentos de herança verdadeiros, e implements quando você precisar de flexibilidade ou quiser impor um contrato sem compartilhar detalhes de implementação.

challenge icon

Desafio

Fácil

Vamos construir um sistema de trabalhadores que demonstra quando usar extends versus implements. Você criará uma classe base de trabalhador e, em seguida, mostrará ambas as abordagens: uma classe que verdadeiramente "é um" trabalhador e herda o comportamento, e outra que simplesmente "pode fazer" o que um trabalhador faz, mas com uma lógica completamente personalizada.

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

  • worker.dart: Defina sua hierarquia de trabalhadores aqui:
    • Uma classe Worker com uma propriedade String name e um construtor. Inclua um método work() que imprime [name] is working... e um método takeBreak() que imprime [name] takes a coffee break
    • Uma classe OfficeWorker que estende (extends) Worker. Adicione uma propriedade String department. Sobrescreva work() para imprimir [name] is typing reports in [department] mas mantenha o comportamento herdado de takeBreak()
    • Uma classe RobotWorker que implementa (implements) Worker. Adicione uma propriedade String model. Como robôs não são realmente trabalhadores, mas podem fazer o que trabalhadores fazem, forneça implementações completamente personalizadas: work() deve imprimir Robot [model] is assembling parts e takeBreak() deve imprimir Robot [model] is recharging
  • main.dart: Importe seu arquivo de trabalhador e demonstre ambas as abordagens:
    • Crie um OfficeWorker chamado 'Alice' no departamento 'Marketing'
    • Crie um RobotWorker com o modelo 'RX-7'
    • Para o trabalhador de escritório, chame work() e depois takeBreak()
    • Imprima uma linha vazia
    • Para o robô trabalhador, chame work() e depois takeBreak()

Observe como OfficeWorker herda takeBreak() automaticamente porque estende Worker - ele verdadeiramente "é um" trabalhador. Enquanto isso, o RobotWorker deve fornecer sua própria implementação para tudo porque ele apenas implementa a interface - ele "pode fazer" o que um trabalhador faz, mas do seu próprio jeito robótico.

Saída esperada:

Alice is typing reports in Marketing
Alice takes a coffee break

Robot RX-7 is assembling parts
Robot RX-7 is recharging

Folha de consulta

Use extends para herdar comportamento de uma classe pai. A subclasse recebe automaticamente todos os métodos do pai e pode sobrescrevê-los:

class Animal {
  void breathe() {
    print('Breathing...');
  }
}

class Dog extends Animal {
  void bark() {
    print('Woof!');
  }
}

void main() {
  var dog = Dog();
  dog.breathe();  // Herdado automaticamente
  dog.bark();
}

Use implements para garantir uma estrutura sem herdar código. Você deve fornecer sua própria implementação para cada método:

class Robot implements Animal {
  @override
  void breathe() {
    print('Ventilating circuits...');
  }
}

Principais diferenças:

  • extends: "Eu sou um tipo disso" - herança verdadeira com código compartilhado
  • implements: "Eu posso fazer o que isso faz" - impõe um contrato com lógica personalizada
  • Você só pode estender uma classe, mas pode implementar múltiplas interfaces

Escolha extends para relacionamentos pai-filho verdadeiros onde o comportamento deve ser herdado. Escolha implements quando precisar de flexibilidade ou quiser impor um contrato sem compartilhar a implementação.

Experimente você mesmo

import 'worker.dart';

void main() {
  // TODO: Crie um OfficeWorker chamado 'Alice' no departamento 'Marketing'
  
  // TODO: Crie um RobotWorker com o modelo 'RX-7'
  
  // TODO: Para o trabalhador de escritório, chame work() e depois takeBreak()
  
  // TODO: Imprima uma linha vazia
  
  // TODO: Para o trabalhador robô, chame work() e depois takeBreak()
}
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