Universo DC - Aprenda POO com exemplos práticos
Entender o conceito de Classes Abstratas e quando utilizá-las, usando o universo DC como exemplo.
Uma classe abstrata é uma classe que não pode ser instanciada diretamente. Ela serve como base para outras classes e pode conter métodos abstratos (sem implementação) que devem ser implementados pelas classes filhas.
Analogia: Uma classe abstrata é como um molde incompleto. Você não pode criar objetos diretamente dela, mas pode criar objetos das classes que a completam.Use quando:
// TÓPICO: Classe Abstrata
// 'abstract' indica que esta classe não pode ser instanciada diretamente
// Você não pode fazer: Personagem p = new Personagem(); ❌
// Mas pode fazer: Heroi h = new Heroi(); ✅ (se Heroi herda de Personagem)
public abstract class Personagem
{
// Propriedades comuns a todos os personagens
public string Nome { get; set; }
public int Nivel { get; set; }
// Construtor (mesmo sendo abstrata, pode ter construtor)
public Personagem(string nome, int nivel)
{
Nome = nome;
Nivel = nivel;
}
// TÓPICO: Método Concreto (com implementação)
// Métodos concretos têm implementação e podem ser usados diretamente
public void SubirNivel()
{
Nivel++;
Console.WriteLine($"{Nome} subiu para o nível {Nivel}!");
}
// TÓPICO: Método Abstrato (sem implementação)
// Métodos abstratos NÃO têm implementação
// Classes filhas SÃO OBRIGADAS a implementar este método
// Cada tipo de personagem tem sua forma única de usar poder
public abstract void UsarPoder();
// Outro método abstrato
// Cada personagem se apresenta de forma diferente
public abstract void Apresentar();
// TÓPICO: Método Virtual (pode ser sobrescrito, mas tem implementação padrão)
// Diferente do abstrato, o virtual tem implementação
// Classes filhas podem usar a implementação padrão ou sobrescrever
public virtual void Descansar()
{
Console.WriteLine($"{Nome} está descansando...");
}
}
// Versão mais concisa
public abstract class Personagem
{
public string Nome { get; set; }
public int Nivel { get; set; }
public Personagem(string nome, int nivel)
{
Nome = nome;
Nivel = nivel;
}
// Método concreto abreviado
public void SubirNivel() =>
Console.WriteLine($"{Nome} subiu para o nível {++Nivel}!");
// Métodos abstratos (devem ser implementados nas classes filhas)
public abstract void UsarPoder();
public abstract void Apresentar();
// Método virtual (implementação padrão, pode ser sobrescrito)
public virtual void Descansar() =>
Console.WriteLine($"{Nome} está descansando...");
}
// TÓPICO: Implementação de Classe Abstrata
// Heroi DEVE implementar todos os métodos abstratos de Personagem
public class Heroi : Personagem
{
public string Equipe { get; set; }
public int VidasSalvas { get; set; }
public Heroi(string nome, int nivel, string equipe) : base(nome, nivel)
{
Equipe = equipe;
VidasSalvas = 0;
}
// TÓPICO: Implementação Obrigatória de Método Abstrato
// DEVE implementar UsarPoder() (obrigatório, vem de Personagem)
public override void UsarPoder()
{
Console.WriteLine($"{Nome} usa seu poder para proteger os inocentes!");
}
// TÓPICO: Implementação Obrigatória de Método Abstrato
// DEVE implementar Apresentar() (obrigatório, vem de Personagem)
public override void Apresentar()
{
Console.WriteLine($"Olá! Eu sou {Nome}, herói da {Equipe}, nível {Nivel}!");
Console.WriteLine($"Já salvei {VidasSalvas} vidas!");
}
// TÓPICO: Sobrescrita Opcional de Método Virtual
// PODE sobrescrever Descansar() (opcional, já tem implementação em Personagem)
public override void Descansar()
{
Console.WriteLine($"{Nome} descansa na Batcaverna, recuperando forças...");
}
// Método específico de heróis
public void SalvarVida()
{
VidasSalvas++;
Console.WriteLine($"{Nome} salvou uma vida! Total: {VidasSalvas} vidas salvas.");
}
}
// TÓPICO: Implementação de Classe Abstrata
// Vilao também DEVE implementar todos os métodos abstratos
public class Vilao : Personagem
{
public string Organizacao { get; set; }
public int PlanosExecutados { get; set; }
public Vilao(string nome, int nivel, string organizacao) : base(nome, nivel)
{
Organizacao = organizacao;
PlanosExecutados = 0;
}
// TÓPICO: Implementação Obrigatória (diferente da de Heroi)
// Cada classe implementa de forma diferente
public override void UsarPoder()
{
Console.WriteLine($"{Nome} usa seu poder para causar caos e destruição!");
}
// TÓPICO: Implementação Obrigatória (diferente da de Heroi)
public override void Apresentar()
{
Console.WriteLine($"Cuidado! Eu sou {Nome}, vilão da {Organizacao}, nível {Nivel}!");
Console.WriteLine($"Já executei {PlanosExecutados} planos maléficos!");
}
// TÓPICO: Não Sobrescreve Descansar()
// Usa a implementação padrão de Personagem
// (Não precisa sobrescrever, mas pode se quiser)
// Método específico de vilões
public void ExecutarPlano()
{
PlanosExecutados++;
Console.WriteLine($"{Nome} executou um plano maléfico! Total: {PlanosExecutados} planos.");
}
}
// TÓPICO: Instanciação de Classes Derivadas
// Não podemos criar Personagem diretamente (é abstrata)
// Personagem p = new Personagem("Teste", 1); ❌ ERRO!
// Mas podemos criar objetos das classes filhas
Heroi batman = new Heroi("Batman", 85, "Liga da Justiça");
Heroi superman = new Heroi("Superman", 100, "Liga da Justiça");
Vilao coringa = new Vilao("Coringa", 80, "Legião do Mal");
Vilao lexLuthor = new Vilao("Lex Luthor", 75, "Legião do Mal");
// Usando métodos abstratos (cada um implementa diferente)
batman.UsarPoder(); // "Batman usa seu poder para proteger os inocentes!"
coringa.UsarPoder(); // "Coringa usa seu poder para causar caos e destruição!"
batman.Apresentar(); // Apresentação de herói
coringa.Apresentar(); // Apresentação de vilão
// Usando método concreto (herdado, funciona igual para todos)
batman.SubirNivel(); // Funciona porque é método concreto
coringa.SubirNivel(); // Funciona porque é método concreto
// Usando método virtual
batman.Descansar(); // Versão sobrescrita (Batcaverna)
coringa.Descansar(); // Versão padrão (da classe base)
// TÓPICO: Polimorfismo com Classes Abstratas
// Podemos tratar objetos de classes derivadas como Personagem
List<Personagem> personagens = new List<Personagem>();
personagens.Add(new Heroi("Batman", 85, "Liga da Justiça"));
personagens.Add(new Heroi("Superman", 100, "Liga da Justiça"));
personagens.Add(new Vilao("Coringa", 80, "Legião do Mal"));
personagens.Add(new Vilao("Lex Luthor", 75, "Legião do Mal"));
// Iterando e chamando métodos abstratos
foreach (Personagem personagem in personagens)
{
// Cada objeto chama sua própria implementação
personagem.UsarPoder(); // Polimorfismo!
personagem.Apresentar(); // Polimorfismo!
Console.WriteLine(); // Linha em branco
}
| Tipo | Implementação | Obrigatório Implementar? | Pode Instanciar Classe? |
|---|---|---|---|
| Abstract | Sem implementação | ✅ SIM (obrigatório) | ❌ NÃO |
| Virtual | Com implementação | ❌ NÃO (opcional) | ✅ SIM (se não for abstract) |
| Concreto | Com implementação | ❌ NÃO | ✅ SIM |
abstract class: Classe que não pode ser instanciadaabstract method: Método sem implementação, obrigatório nas classes filhasvirtual method: Método com implementação padrão, pode ser sobrescritoNa próxima aula, veremos Interfaces e como criar contratos que classes devem seguir.