DEV Community

Yuri Peixinho
Yuri Peixinho

Posted on

LSP - Liskov Substitution Principle (Princípio da Substituição de Liskov)

O terceiro princípio é o Liskov Substituition Principle. Ele foi definido por Barbara Liskov em 1987 e, embora que por definição academia pareça ser um “bicho de setes cabeças”, na prática é bem simples e ideal para criar sistemas robustos.

O princípio diz que: Uma classe derivada deve poder ser substituída por sua classe base sem que o comportamento do programa seja alterado ou quebrado.

Para cumprir o príncpio pense assim: “O filho (classe que herda) deve conseguir fazer tudo que o pai (classe pai) prometeu que faria”. Se o pai diz "eu sei somar dois números", o filho não pode dizer "eu só sei somar se os números forem positivos". Isso seria uma surpresa desagradável para quem usa o código.

Analogia com Pássaros

Imagine que você tem um sistema para um zoológico.

  1. Você cria a Entidade Passaro
  2. Você define que todo Passaro tem a habilidade de voar.

Até aqui, tudo bem. Aí você cria os tipos específicos:

  • Pardal (É um Pássaro): Voa? Sim. ✅ (Tudo certo, segue o princípio).
  • Águia (É um Pássaro): Voa? Sim. ✅ (Tudo certo).

Agora vem o problema. Você precisa adicionar um Pinguim.

  • Pinguim (É um Pássaro): Voa? Não.

Onde o princípio quebra?

Se você tem uma parte do seu código que diz: “Pegue todos os pássaros e faça-os voar”, quando chegar a vez do Pinguim o programa vai travar ou dar erro, porque pinguins não voam. Na aplicação promete que todo pássaro voa, mas o pinguim não cumpre essa promessa.

Como consertar o exemplo do Pinguim?

Em vez de colocar "Voar" na categoria principal Passaro, você deve criar uma categoria mais específica ou separar as habilidades:

  1. Classe `Passaro` (Tem bico, bota ovos).
  2. Classe PassaroQueVoa (Herda de Pássaro + sabe voar).
  3. Classe PassaroQueNada Herda de Pássaro + sabe nadar).

Dessa forma o Pardal entra em PassaroQueVoa e o Peguim em PassaroQueNada

E o melhor: ninguém promete o que não pode cumprir, e o código não quebra.

Exemplo aplicado ao código

Vamos retomar o exemplo acima e desenvolver com o código com C# de duas formas, uma que viola o LSP e outra que não viola.

1. Violação Estrutural

Imagine que você tem uma classe abstrata Passaro. Em C#, é comum usarmos classes abstratas ou interfaces para definir contratos.

O exemplo abaixo viola o LSP porque o Pinguim não pode substituir Passaro sem causar efeitos colaterais (a exceção).

Classe Base

public abstract class Passaro
{
    public abstract void Voar();
}
Enter fullscreen mode Exit fullscreen mode

Implementação Concreta

public class Pardal : Passaro
{
    public override void Voar()
    {
        Console.WriteLine("Pardal voando alto!");
    }
}
Enter fullscreen mode Exit fullscreen mode

Implementação que viola o LSP

public class Pinguim : Passaro
{
    public override void Voar()
    {
        // O compilador obriga a implementar Voar(),
        // mas a lógica não permite. O dev lança uma exceção.
        throw new NotImplementedException("Pinguins não voam!");
    }
}
Enter fullscreen mode Exit fullscreen mode

2. O Jeito Correto

Em C#, a melhor forma de resolver isso é segregando as capacidades através de Interfaces. Nem todo pássaro é um IVoador.

Essa implementação abaixo torna impossível passar um Pinguim para um método que espera IVoador. O compilador do C# vai te impedir antes mesmo de você rodar o programa.

Definição de abstração (interface e classe abstrata)

// Define apenas o que é comum a TODOS
public abstract class Ave 
{
    public void Comer() { Console.WriteLine("Comendo..."); }
}

// Interface (Capacidade) separada
public interface IVoador
{
    void Voar();
}
Enter fullscreen mode Exit fullscreen mode

Implementações

// Pardal é uma Ave E sabe voar
public class Pardal : Ave, IVoador
{
    public void Voar() 
    { 
        Console.WriteLine("Pardal voando!"); 
    }
}

// Pinguim é apenas uma Ave (não implementa IVoador)
public class Pinguim : Ave 
{
    // Pode ter métodos de nadar aqui
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)