LSP - Princípio de Substituição de Liskov
Last updated
Last updated
Barbara Liskov introduziu o Princípio de substituição de Liskov como uma definição particular para o conceito de subtipo. O princípio foi definido de forma resumida como:
Seé uma propriedade demonstrável dos objetos de tipo . Então deve ser verdadeiro para de tipo onde é um subtipo .
Falando de outra maneira, a visão de "subtipo" defendida por Liskov é baseada na noção da substituição; isto é, se S é um subtipo de T, então os objetos do tipo T, em um programa, podem ser substituídos pelos objetos de tipo S sem que seja necessário alterar as propriedades deste programa.
Suponha que uma parte do sistema está utilizando uma determinada funcionalidade. Se essa funcionalidade precisar ser trocada por outra, por meio de polimorfismo dinâmico ou estático, a outra deverá devolver o mesmo tipo de informação, caso contrário, o sistema quebrará.
Neste contexto, para garantir que a classe S tenha o mesmo comportamento que a classe base T, é imprescindível a utilização de um contrato (interface ou classe abstrata), contendo as definições de métodos necessárias para que as classes que a herdarem sejam obrigadas a implementá-las.
Um exemplo clássico para demonstrar uma violação desse princípio é a modelagem de classes Quadrado
e Retangulo
. Todo quadrado é um retângulo? Sim, por definição. Se é um, portanto é lógico e intuitivo modelar uma classe Quadrado
como sendo derivada da classe Retangulo
. Aqui provavelmente conseguiriamos utilizar herança para modelar essas classes. Então teriamos as duas classes da seguinte maneira
E a classe Quadrado
. Perceba que sobrescrevemos os métodos set
para garantir que ele continua sendo um quadrado, ou seja, tenho os lados iguais.
Com isso, a classe derivada viola uma regra estabelecida na classe base: a de que altura e comprimento variam independentemente. E quando isso vai se mostrar um problema? Vejamos o exemplo a seguir
O desenvolvedor facilmente pode assumir que estava lidando com um Retangulo
(afinal, é o tipo do parâmetro do método) e aplicou um cálculo que variasse suas dimensões. No entanto, caso o método receba, em tempo de execução, um objeto do tipo Quadrado
teremos um comportamento inesperado: o cálculo para redimensionar o retângulo o transformará em um quadrado, isto é, ao quadruplicar o comprimento, inadvertidamente, a altura também foi quadruplicada!
O problema acima só existe porque, como dito anteriormente, a classe derivada não respeita a regra da classe base de variar os lados de forma independente. Sendo assim, do ponto de vista computacional, Quadrado não é um Retangulo, pois ambos possuem comportamentos diferentes em relação a alteração de seus lados.
Esse cenário de quebra do princípio ocorre muitas vezes pela nossa intuição de que Herança sempre ocorre quando temos um cenário de "é um", quando na verdade isso não é verdadeiro. Essa idéia ajuda na maioria das oportunidades de Herança, mas é sempre bom ter em mente o Princípio de Substituição de Liskov para verificarmos se realmente faz sentido.