Interfaces vs Abstract Classes
Quando usar cada um, como se complementam, e por que importa para design, testabilidade e versionamento
Regra de ouro: Interfaces definem capacidades (contratos sem estado) e suportam heranca multipla. Abstract classes fornecem estado + implementacao compartilhada e sao ideais para patterns como Template Method. C# 8+ tem default interface methods, mas use com moderacao.
Arvore de decisao
Quando escolher Interface
Interface - use quando:
- Precisa de heranca multipla de contratos (capacidades)
- Quer DI seams para injecao de dependencia e mocking em testes
- Quer desacoplar features de hierarquias de classes base
- A classe precisa implementar multiplos comportamentos ortogonais
- Vai expor uma API publica que outros consumidores implementam
Abstract Class - use quando:
- Precisa de estado/campos compartilhados ou protected helpers
- Quer fornecer uma implementacao base reutilizavel
- Controla a base e espera evoluir (adicionar virtual members sem quebrar)
- Precisa de construtores para inicializacao garantida
- Quer aplicar o pattern Template Method (orquestracao + passos overridable)
Na pratica, combine os dois: Defina uma interface para o contrato (DI/mocking), depois crie uma abstract class que a implementa com logica compartilhada. Classes concretas herdam da abstract e implementam os detalhes.
Exemplo A - Diferencas fundamentais
Interface define o contrato (Area()), abstract class adiciona estado compartilhado (Color):
// Interface define contrato β sem estado
public interface IShape
{
double Area();
}
// Abstract class adiciona estado + implementacao compartilhada
public abstract class ShapeBase : IShape
{
public string Color { get; init; } = "Black"; // shared state
public abstract double Area(); // derived must implement
}
// Classe concreta β herda estado e implementa o contrato
public sealed class Circle : ShapeBase
{
public double Radius { get; init; }
public override double Area() => Math.PI * Radius * Radius;
}
Por que nao colocar tudo numa interface com default methods?
Default interface methods (C# 8+) nao podem acessar estado (campos de instancia). Abstract classes podem ter campos, construtores e protected helpers. Alem disso, default methods adicionam complexidade (diamond problem) e nao sao invocaveis diretamente pela classe implementadora β apenas via cast para a interface.
Exemplo B - Multiplas interfaces, uma base class
Rectangle herda de uma abstract base (RenderableShape) e implementa multiplas interfaces:
// Interfaces modelam capacidades ortogonais
public interface IHasPerimeter { double Perimeter(); }
public interface IRenderable { void Render(); }
// Abstract class combina interface + logica compartilhada
public abstract class RenderableShape : IShape, IRenderable
{
public abstract double Area();
public virtual void Render() => Console.WriteLine("Rendering a shape...");
}
// Classe concreta: herda UMA base, implementa MUITAS interfaces
public sealed class Rectangle : RenderableShape, IHasPerimeter
{
public double W { get; init; }
public double H { get; init; }
public override double Area() => W * H;
public double Perimeter() => 2 * (W + H);
public override void Render() => Console.WriteLine($"Rect {W}x{H}, area={Area()}");
}
C# suporta heranca multipla de classes?
Nao. Uma classe pode herdar de apenas uma classe base, mas pode implementar quantas interfaces quiser. Interfaces modelam capacidades ortogonais (IHasPerimeter, IRenderable), enquanto a abstract class centraliza logica compartilhada.