Menu
Coddy logo textTech

Implementação vs. Extensão

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 extends quanto implements, vamos esclarecer quando usar cada um.

Use extends quando quiser herdar comportamento. Sua subclasse recebe todo o código da classe pai gratuitamente e pode desenvolvê-lo:

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 quiser 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 disto”, enquanto implements diz “Eu consigo fazer o que isto 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 relações de herança verdadeiras e implements quando precisar de flexibilidade ou quiser impor um contrato sem compartilhar detalhes de implementação.

challenge icon

Desafio

Fácil

Vamos criar um sistema de trabalhadores que demonstra quando usar extends em vez de implements. Você criará uma classe base de trabalhador e, em seguida, mostrará as duas abordagens: uma classe que realmente “é um” trabalhador e herda comportamentos, 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 Worker. Adicione uma propriedade String department. Substitua work() para imprimir [name] is typing reports in [department], mas mantenha o comportamento herdado de takeBreak()
    • Uma classe RobotWorker que implementa Worker. Adicione uma propriedade String model. Como robôs não são realmente trabalhadores, mas podem fazer o que os 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 trabalhadores e demonstre as duas abordagens:
    • Crie um OfficeWorker chamado 'Alice' no departamento 'Marketing'
    • Crie um RobotWorker com o modelo 'RX-7'
    • Para o trabalhador do escritório, chame work() e depois takeBreak()
    • Imprima uma linha vazia
    • Para o trabalhador robô, chame work() e depois takeBreak()

Observe como OfficeWorker herda takeBreak() automaticamente porque estende Worker — ele realmente “é um” trabalhador. Enquanto isso, RobotWorker precisa fornecer sua própria implementação para tudo porque apenas implementa a interface — ele “pode fazer” o que um trabalhador faz, mas à sua própria maneira robótica.

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

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 office worker, chame work() e depois takeBreak()
  
  // TODO: Imprima uma linha vazia
  
  // TODO: Para o robot worker, 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

Pratique por conta própria: Compilador de Dart online