Categorias do Site

Princípio de Substituição de Liskov: Guia Completo

Descubra o Princípio de Substituição de Liskov e como ele garante a robustez e flexibilidade do código em design orientado a objetos.

Cubo tridimensional com texturas de fumaça em tons de roxo, azul e rosa, contendo as letras

Os princípios SOLID são considerados regras de ouro para criar um código robusto e flexível. Criados pelo renomado Robert C. Martin, eles são fundamentais para um design orientado a objetos limpo e sustentável:

  1. Princípio da Responsabilidade Única (SRP)
  2. Princípio Aberto/Fechado (OCP)
  3. Princípio de Substituição de Liskov (LSP)
  4. Princípio da Segregação de Interfaces (ISP)
  5. Princípio da Inversão de Dependência (DIP)

O Princípio de Substituição de Liskov (LSP) é o herói desconhecido que garante que substituir um objeto por outro não quebre seu sistema. Ele reforça a estrutura lógica e a confiabilidade em seu código:

O que é o LSP?

Nomeado em homenagem à cientista da computação Barbara Liskov, este princípio é baseado na ideia de que você deve poder substituir uma classe pai por uma de suas subclasses sem quebrar seu código.

Por exemplo, um software projetado para carros autônomos deve funcionar com qualquer veículo. Se funcionar bem com um carro, mas falhar com um caminhão, o LSP foi violado. O código confiou demais no pai e não considerou o comportamento dos filhos.

Por que o LSP é importante?

O LSP é essencial para a extensão dos sistemas. Um sistema que segue o LSP oferece:

  • Sem falhas inesperadas – A troca de subclasses não quebra o programa, pois são consistentes com a superclasse.
  • Expansão sem medo – LSP garante que novos elementos se integrem sem problemas adicionais.
  • Correção facilitada – Permite ajustes sem reescrever todo o código.
  • Testes simplificados – Comportamentos consistentes tornam os testes mais fáceis.

Substituir subclasses sem quebrar o código

No cerne do LSP está a confiança. Você deve substituir uma classe pai por uma classe filha e esperar que tudo funcione bem. Uma subclasse não deve exigir mais do que a classe pai ou entregar menos do que prometido.

Pré-condições

São as condições que devem ser verdadeiras antes de um método ser executado. Uma subclasse não deve exigir mais do que a superclasse.

Pós-condições

São os resultados garantidos após a execução de um método. A subclasse não deve entregar menos do que a superclasse prometeu.

Entendendo o LSP com uma analogia do mundo real

Parece lógico dizer que um quadrado é um retângulo com lados iguais, certo? No entanto, ao tratar o quadrado como subclasse de um retângulo, violamos o LSP. A classe Quadrado que impõe lados iguais não pode substituir de forma confiável uma classe Retângulo que pressupõe largura e altura independentes.

Violações do LSP: O que dá errado e como corrigir

Mesmo compreendendo o LSP, é fácil violá-lo. A violação pode surgir quando a subclasse altera um comportamento prometido pela superclasse, causando exceções inesperadas.

Problema do quadrado-retângulo: Quando a subclasse leva a comportamentos incorretos

Ao forçar uma relação de herança onde o comportamento diverge, é melhor manter entidades separadas, permitindo que existam como formas independentes que compartilham características em comum.

Métodos lançando exceções inesperadas

O LSP é frequentemente violado quando uma subclasse remove ou altera um comportamento prometido pela superclasse, resultando em exceções inesperadas.

Valores de retorno inesperados

Outra violação comum do LSP ocorre quando uma subclasse retorna algo inesperado, que o sistema não está preparado para lidar.

LSP em diferentes linguagens de programação

Independentemente da linguagem de programação, a ideia central do Liskov Substitution Principle (LSP) permanece a mesma: subclasses devem ser substitutos confiáveis para suas superclasses.

LSP em Python

No Python, a tipagem dinâmica e o duck typing exigem cuidado para garantir que a subclasse se comporte como a superclasse.

from abc import ABC, abstractmethod

class Bird(ABC):
   @abstractmethod
   def fly(self) -> None:
       pass

class Sparrow(Bird):
   def fly(self) -> None:
       print("Sparrow flying")  # satisfaz o contrato
# Código cliente
def let_it_fly(b: Bird):
   b.fly()

Programando para uma base abstrata, qualquer subclasse que suporte fly() pode ser usada de forma intercambiável.

LSP em Java

Java, com seu sistema de tipos estáticos, reforça a necessidade do LSP, garantindo que subclasses possam se integrar sem comprometer a estrutura.

interface Shape {
   double area();
}
class Circle implements Shape {
   private final double radius;
   public Circle(double r) { radius = r; }
   public double area() { return Math.PI * radius * radius; }
}

Qualquer subclasse que implemente area() deve respeitar o contrato original, sem efeitos colaterais inesperados, e o resultado deve ser sempre um valor positivo.

LSP em TypeScript

Em TypeScript, a tipagem estática garante que subclasses mantenham assinaturas de método consistentes.

interface ButtonProps { onClick: () => void; label: string; }


function PrimaryButton(props: ButtonProps) {
   return ;
}


function IconButton(props: ButtonProps & { icon: string }) {
   return ;
}

IconButton estende os props sem remover ou alterar nenhum dos campos obrigatórios.

LSP em C#

O C# utiliza classes abstratas e interfaces para garantir ordem e estrutura, mantendo a consistência de comportamento.

public interface IRepository {
   T GetById(int id);
}
public class SqlRepository : IRepository {
   public T GetById(int id) {
       // buscar no banco de dados SQL
   }
}

Os repositórios concretos devem cumprir garantias em torno de retornos não nulos e tratamento adequado de exceções.

LSP no desenvolvimento de software moderno

O Princípio de Substituição de Liskov continua a ser valioso em sistemas modernos, garantindo que arquiteturas complexas funcionem de forma confiável.

LSP em programação funcional e injeção de dependência

No contexto de injeção de dependência e programação funcional, o LSP garante que funções ou serviços substituíveis não introduzam surpresas comportamentais inesperadas.

LSP em componentes React e serviços Angular

Ao projetar componentes React, o LSP garante que o comportamento esperado seja mantido consistentemente. Em Angular, o princípio assegura a consistência e previsibilidade dos serviços.

Angular services:
@Injectable({ providedIn: 'root' })
export abstract class AuthService {
   abstract login(credentials: Credential): Observable;
}


@Injectable()
export class RealAuthService extends AuthService {
   login(c: Credential) { /* chamada http */ }
}

Os clientes devem poder alternar entre implementações simuladas e reais sem alterar o comportamento esperado.

LSP em arquiteturas de microsserviços

No contexto de microsserviços, o LSP é crucial para manter a compatibilidade de APIs à medida que os serviços evoluem, garantindo transições suaves entre diferentes versões de serviço.

Comparando LSP com outros princípios SOLID

O LSP tem uma relação importante com outros princípios SOLID. Ele atua como guardião, garantindo que o sistema permaneça seguro e estável à medida que cresce.

Melhores práticas para implementar o Princípio de Substituição de Liskov

Recomendações para aplicar o LSP efetivamente:

Refatorar com confiança: Lidando com violações do LSP

Diretrizes para refatorar código que viola o LSP:

  • Se as subclasses não se comportam como esperado, o problema pode estar em uma classe base muito ativa. Aplique a segregação de interfaces para definir contratos menores e mais focados.
  • Considere usar delegação ou composição para compartilhar comportamento de forma mais segura e flexível.
  • Quando possível, mova o comportamento para classes de estratégia que possam ser injetadas, em vez de substituídas, mantendo as responsabilidades claras e evitando quebrar o contrato do pai.

Testando o LSP: Como garantir que as subclasses se comportem corretamente

Para estruturar testes que sigam o LSP:

  • Escreva testes que validem o comportamento esperado da superclasse.
  • Execute os mesmos testes em todas as subclasses.
  • Verifique se cada subclasse lida com entradas conforme esperado.
  • Confirme que os resultados permanecem consistentes com o que a superclasse promete.

Essa abordagem ajuda a garantir que suas subclasses realmente se comportem como substituições diretas.

A herança nem sempre é a resposta: Tente composição em vez disso

O LSP é frequentemente violado quando a herança é usada de forma inadequada. Muitas vezes, a composição, que constrói comportamento combinando partes menores e focadas, pode ser uma alternativa mais limpa e confiável.

Considerações finais sobre o Princípio de Substituição de Liskov

O Liskov Substitution Principle (LSP) é essencial para a escrita de código que funciona. Ele garante que as subclasses possam substituir suas superclasses sem causar problemas inesperados.

Claro, o LSP não está sozinho. Ele funciona em conjunto com outros princípios SOLID, como SRP e OCP, ajudando na construção de aplicativos modulares, escaláveis e fáceis de testar.

Como regra geral: se sua subclasse pode substituir sua superclasse sem quebrar nada, você está no caminho certo com o LSP.

  • Enfrentando a Complexidade com GraphQL

    Descubra como GraphQL facilita o desenvolvimento de soluções inteligentes com IA.

    Descubra como GraphQL facilita o desenvolvimento de soluções inteligentes com IA.

    Ler notícia completa
    Banner de podcast da UX Magazine intitulado
  • UX: Emoções Além das Telas no Design

    Descubra como o design emocional transforma experiências, indo além das telas e criando conexões humanas.

    Descubra como o design emocional transforma experiências, indo além das telas e criando conexões humanas.

    Ler notícia completa
    Símbolo abstrato em tons de marrom e laranja que se assemelha a uma pessoa estilizada com braços estendidos e uma perna erguida.
  • Como usar CSS line-clamp para limitar texto

    Aprenda a usar a propriedade CSS line-clamp para limitar linhas de texto e melhorar a aparência do layout.

    Aprenda a usar a propriedade CSS line-clamp para limitar linhas de texto e melhorar a aparência do layout.

    Ler notícia completa
    Fundo gradiente em tons de laranja e violeta com o texto
  • Promise.all ainda é relevante em 2025?

    Antes das promises serem introduzidas nativamente no JavaScript, usávamos muitos callbacks para tarefas assíncronas. É comum ver callbacks sendo usados, pois muitos desenvolvedores podem ainda pensar que callbacks e promises são o mesmo, mas não são. Quando promises foram introduzidas, substituíram amplamente os callbacks, tornando a sintaxe mais compreensível. Em 2025, com async/await, Promise.allSettled, Promise.any […]

    Promise.all é crucial para tarefas assíncronas, mas novas alternativas surgem em 2025. Saiba quando usá-lo.

    Ler notícia completa
    Logotipo do JavaScript (JS) em quadrado amarelo sobre fundo com ondas suaves em tons de branco e cinza claro.
  • Equilibrando IA e UX: O Desafio do Design Humanizado

    A IA está sendo integrada aos fluxos de trabalho de design modernos, ajudando na geração de conteúdo, ideação e prototipagem. Isso aumenta a eficiência das equipes de design, aprimorando a forma como criamos, pensamos e resolvemos problemas. No entanto, a IA também traz preocupações ao processo de design, como a possível perda de foco no […]

    Descubra como manter o design UX humanizado enquanto utiliza IA para otimizar processos e aumentar a produtividade.

    Ler notícia completa
    Mão robótica branca tocando a ponta do dedo de uma mão humana contra um fundo colorido em tons de arco-íris.
  • A Revolução dos Navegadores com IA: Impactos e Futuro

    Há uma revolução silenciosa ocorrendo em um software que você usa diariamente, mas raramente pensa sobre: o navegador. Chrome, Safari, Firefox têm sido nossas janelas para a web por décadas. Agora, algo significativo está acontecendo. Uma nova espécie de navegador está surgindo: o navegador com IA. Ele não apenas muda como navegamos, mas redefine o […]

    Navegadores com IA estão mudando a web, impactando a criatividade, economia e verdade online.

    Ler notícia completa
    Tela de interface do Instacart mostrando produtos essenciais para praia à venda, como protetor solar e toalhas, com uma janela de chat com o assistente virtual aberta.
  • As 3 previsões para o futuro do design UX

    A evolução tecnológica moderniza e melhora todas as áreas da tecnologia, incluindo o design de dispositivos digitais, automação, desenvolvimento de software e design UI/UX. Essa evolução e as inovações em HCI (Interação Humano-Computador) impulsionam o design UI/UX para ajudar designers a criar produtos digitais mais amigáveis, usáveis e produtivos para todos os usuários. O design […]

    Confira as três principais previsões para a próxima era do design UX e como elas podem impactar o futuro das interfaces digitais.

    Ler notícia completa
    Ilustração em 3D de um computador desktop moderno com ícones em estilo futurista na tela, sobre fundo roxo com linhas de rede digitais.
  • A Importância do Enquadramento no Design

    No design, o enquadramento do problema está se tornando o cerne do papel humano. À medida que a IA, ou o que chamo de Programa, assume mais o trabalho de solução, nosso ofício muda para como tratamos o problema. “A IA não está substituindo designers; está substituindo designers que focam em saídas automatizáveis.” Citação e […]

    Explorando como o enquadramento de problemas redefine o papel humano no design em tempos de IA.

    Ler notícia completa
    Imagem de rabisco em preto e branco cheia de palavras e desenhos, incluindo cabeças estilizadas, uma palavra
  • Psicologia Ética no E-commerce: Facilite Compras

    A psicologia no e-commerce tem uma má reputação, muitas vezes associada a táticas de manipulação como escassez artificial e cobranças ocultas. No entanto, existe um lado positivo: a facilitação das compras sem manipulação. Trabalhando anos com e-commerce, percebi que a maioria dos problemas de conversão está em facilitar o processo de compra. Vou mostrar quatro […]

    Aprenda como remover barreiras psicológicas no e-commerce, promovendo compras éticas sem manipulação.

    Ler notícia completa
    Ilustração de um trator removendo neve da estrada, com carros vermelhos parcialmente cobertos de neve ao lado. Ambiente frio com árvores ao fundo.