Menu
Coddy logo textTech

Interface vs Classe Abstrata

Parte da seção Programação Orientada a Objetos do Journey de C# da Coddy. Lição 26 de 70.

Tanto as interfaces quanto as classes abstratas permitem definir contratos que outras classes devem seguir, mas elas têm finalidades diferentes e capacidades distintas.

Uma interface define o que uma classe deve fazer, sem qualquer implementação. É um contrato puro:

public interface IFlyable
{
    void Fly();
}

public class Bird : IFlyable
{
    public void Fly()
    {
        Console.WriteLine("Flapping wings");
    }
}

Uma classe abstrata pode fornecer tanto um contrato quanto uma implementação compartilhada. Ela é um projeto parcial:

public abstract class Vehicle
{
    public string Brand { get; set; }
    
    public void StartEngine()
    {
        Console.WriteLine("Engine started");
    }
    
    public abstract void Drive();  // Deve ser implementado
}

public class Car : Vehicle
{
    public override void Drive()
    {
        Console.WriteLine("Driving on roads");
    }
}

As principais diferenças se resumem às regras de herança e à finalidade.

Uma classe pode implementar várias interfaces, mas herdar de apenas uma classe abstrata.

Use uma interface quando classes não relacionadas precisarem compartilhar comportamento (como IFlyable para pássaros e aviões). Use uma classe abstrata quando classes relacionadas compartilharem código e estado comuns (como veículos que compartilham um mecanismo de partida do motor).

Classes abstratas podem ter construtores, campos e modificadores de acesso em membros. Tradicionalmente, as interfaces não podiam, embora o C# moderno permita implementações padrão.

Quando estiver em dúvida, prefira interfaces pela flexibilidade — você sempre poderá adicionar uma classe abstrata posteriormente se uma implementação compartilhada se tornar necessária.

challenge icon

Desafio

Fácil

Vamos criar um sistema de reprodução de mídia que demonstra quando usar interfaces em vez de classes abstratas. Você criará um design no qual dispositivos não relacionados compartilham o comportamento de reprodução por meio de uma interface, enquanto tipos de mídia relacionados compartilham uma implementação comum por meio de uma classe abstrata.

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

  • IPlayable.cs: Defina uma interface chamada IPlayable no namespace Media. Essa interface representa o contrato para qualquer coisa capaz de reproduzir mídia — seja um telefone, uma TV ou um reprodutor de música dedicado. Ela deve declarar um único método Play() que retorna uma string.
  • MediaFile.cs: Defina uma classe abstrata chamada MediaFile no namespace Media. Ela representa a base compartilhada para todos os arquivos de mídia. Ela deve ter uma propriedade Title (string) e uma propriedade Duration (int, representando segundos). Inclua um construtor que defina ambos os valores. Adicione um método concreto chamado GetInfo() que retorna "{Title} ({Duration}s)". Declare também um método abstrato GetType() que retorna uma string — cada tipo de mídia definirá que tipo de arquivo ele é.
  • AudioFile.cs: Defina uma classe AudioFile no namespace Media que herda de MediaFile e implementa IPlayable. Adicione uma propriedade Artist (string). O construtor deve aceitar título, duração e artista. Substitua GetType() para retornar "Audio". Implemente Play() para retornar "Playing audio: {Title} by {Artist}".
  • Program.cs: No arquivo principal, crie um AudioFile usando os valores de entrada. Demonstre ambos os aspectos da classe: chame GetInfo() e GetType() (herdados da classe abstrata) e, em seguida, chame Play() (da interface). Armazene o arquivo de áudio em uma variável IPlayable e chame Play() novamente para mostrar o polimorfismo da interface.

Você receberá três entradas:

  • Título da música
  • Duração em segundos
  • Nome do artista

Imprima a saída neste formato:

Info: {GetInfo() result}
Type: {GetType() result}
Direct: {Play() result}
Via Interface: {Play() result from IPlayable variable}

Por exemplo, se as entradas forem Bohemian Rhapsody, 354 e Queen, a saída deverá ser:

Info: Bohemian Rhapsody (354s)
Type: Audio
Direct: Playing audio: Bohemian Rhapsody by Queen
Via Interface: Playing audio: Bohemian Rhapsody by Queen

Observe como AudioFile se beneficia de ambas as abordagens: ele herda a implementação compartilhada (GetInfo()) da classe abstrata e, ao mesmo tempo, cumpre o contrato de IPlayable. A classe abstrata fornece reutilização de código para tipos de mídia relacionados, enquanto a interface permite que qualquer classe não relacionada seja "reproduzível" sem compartilhar uma hierarquia de herança.

Experimente você mesmo

using System;
using Media;

class Program
{
    public static void Main(string[] args)
    {
        // Ler os valores de entrada
        string title = Console.ReadLine();
        int duration = Convert.ToInt32(Console.ReadLine());
        string artist = Console.ReadLine();
        
        // TODO: Crie um AudioFile usando os valores de entrada
        
        // TODO: Imprima Info: seguido do resultado de GetInfo()
        
        // TODO: Imprima Type: seguido do resultado de GetType()
        
        // TODO: Imprima Direct: seguido do resultado de Play()
        
        // TODO: Armazene o arquivo de áudio em uma variável IPlayable
        
        // TODO: Imprima Via Interface: seguido do resultado de Play() da variável IPlayable
    }
}
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 C# online