Menu
Coddy logo textTech

Interface vs Classe Abstrata

Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy — lição 30 de 91.

Agora que você aprendeu tanto interfaces quanto classes abstratas, vamos esclarecer quando usar cada uma. Embora elas possam parecer semelhantes, elas servem a propósitos diferentes e possuem capacidades distintas.

Recurso Interface Classe Abstrata
Métodos Apenas assinaturas de métodos Tanto métodos abstratos quanto concretos
Propriedades Apenas constantes Pode ter propriedades
Herança múltipla Uma classe pode implementar várias Uma classe pode estender apenas uma
Construtor Não permitido Pode ter construtor

Use uma interface quando você deseja definir um contrato que classes não relacionadas podem cumprir. Por exemplo, tanto um Printer quanto um Logger podem implementar uma interface Writable, mesmo que não compartilhem um ancestral comum.

Use uma classe abstrata quando você tem classes relacionadas que compartilham código comum. Se suas classes Dog e Cat ambas precisarem da mesma implementação do método eat(), uma classe abstrata Animal permite que você escreva esse código uma única vez.

Você também pode combinar ambas as abordagens. Uma classe pode estender uma classe abstrata enquanto implementa múltiplas interfaces:

<?php
abstract class Animal {
    protected $name;
    
    public function eat() {
        return $this->name . " is eating";
    }
}

interface Swimmable {
    public function swim();
}

class Duck extends Animal implements Swimmable {
    public function __construct($name) {
        $this->name = $name;
    }
    
    public function swim() {
        return $this->name . " is swimming";
    }
}

Ponto Chave: Escolha interfaces para definir capacidades em classes não relacionadas. Escolha classes abstratas quando precisar compartilhar código entre classes relacionadas.

challenge icon

Desafio

Fácil

Vamos construir um sistema de veículos que demonstra quando usar uma classe abstrata versus uma interface — e como combinar ambas as abordagens de forma eficaz.

Você criará um sistema onde os veículos compartilham propriedades comuns por meio de herança, mas também podem ganhar capacidades adicionais por meio de interfaces. Isso reflete decisões de design do mundo real: um carro "é um" veículo (herança), mas também "tem a capacidade" de ser reabastecível (interface).

Organize seu código em quatro arquivos:

  • Refuelable.php — Defina uma interface Refuelable com uma única assinatura de método: refuel($amount). Esta capacidade pode ser aplicada a qualquer classe que precise de reabastecimento, independentemente de sua hierarquia de herança.
  • Vehicle.php — Defina uma classe abstrata Vehicle que fornece funcionalidade compartilhada para todos os veículos. Ela deve ter uma propriedade protegida $brand e uma propriedade protegida $fuelLevel (começando em 0). O construtor aceita o nome da marca. Inclua um método concreto getBrand() que retorna a marca, um método concreto getFuelLevel() que retorna o nível de combustível atual e um método abstrato drive() que as classes filhas devem implementar.
  • Car.php — Crie uma classe Car que estende Vehicle e implementa Refuelable. Inclua ambos os arquivos necessários no topo. O construtor aceita a marca e a passa para o construtor pai. Implemente drive() para retornar "[brand] car is driving". Implemente refuel($amount) para adicionar a quantidade ao nível de combustível e retornar "[brand] refueled to [fuelLevel] liters".
  • main.php — Inclua o arquivo Car. Você receberá duas entradas: um nome de marca e uma quantidade de combustível (converta para inteiro). Crie um Car com a marca. Imprima o resultado de drive() na primeira linha e, em seguida, imprima o resultado de refuel() com a quantidade de combustível na segunda linha.

Este desafio ilustra a distinção fundamental: a classe abstrata Vehicle compartilha código e estabelece uma relação de "é um", enquanto a interface Refuelable adiciona uma capacidade que poderia ser aplicada a outras classes não relacionadas (como um gerador ou um barco) sem exigir que sejam veículos.

Folha de consulta

Interfaces e classes abstratas servem a propósitos diferentes:

Recurso Interface Classe Abstrata
Métodos Apenas assinaturas de métodos Tanto métodos abstratos quanto concretos
Propriedades Apenas constantes Pode ter propriedades
Herança múltipla Uma classe pode implementar várias Uma classe pode estender apenas uma
Construtor Não permitido Pode ter construtor

Use uma interface para definir um contrato para classes não relacionadas. Use uma classe abstrata para compartilhar código comum entre classes relacionadas.

Uma classe pode estender uma classe abstrata enquanto implementa múltiplas interfaces:

<?php
abstract class Animal {
    protected $name;
    
    public function eat() {
        return $this->name . " is eating";
    }
}

interface Swimmable {
    public function swim();
}

class Duck extends Animal implements Swimmable {
    public function __construct($name) {
        $this->name = $name;
    }
    
    public function swim() {
        return $this->name . " is swimming";
    }
}

Experimente você mesmo

<?php
require_once 'Car.php';

// Ler a entrada
$brand = trim(fgets(STDIN));
$fuelAmount = intval(trim(fgets(STDIN)));

// TODO: Criar um Carro com a marca

// TODO: Imprimir o resultado de drive() na primeira linha

// TODO: Imprimir o resultado de refuel() com a quantidade de combustível na segunda linha
?>
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