O princÃpio de substituição de Liskov afirma que um pedaço de código deve permanecer correto se uma superclasse for substituÃda por sua subclasse (parafraseando). O que eu não entendo; Por que nos importamos com essa propriedade? Ela torna nosso código mais reutilizável, flexÃvel ou sustentável?
Eu apreciaria um exemplo de código que respeitasse o princÃpio e que o violasse ao explicar a relevância da propriedade de substituição.
Se essa fosse a única coisa que o princÃpio declarava, dificilmente faria sentido perguntar por que nos importamos com isso. Considere o que o oposto desse princÃpio significaria: Que um pedaço de código não deveria permanecer correto se uma superclasse fosse substituÃda por sua subclasse?
Quem iria querer que seu software estivesse incorreto?
O que o PrincÃpio de Substituição de Liskov (LSP) realmente diz é que uma subclasse pode ampliar pré-condições e restringir pós-condições, mas não o contrário.
Isso faz muito sentido, se você pensar a respeito. Considere um método simples que recebe um inteiro como entrada.
Se a superclasse declara que todo inteiro
i
é válido, então o que aconteceria se uma subclasse apertasse a pré-condição? Você pode, por exemplo, implementar uma subclasse que divide algum número pori
. Se você fizer isso, no entanto, o valor de entrada0
agora causaria um erro de divisão por zero na subclasse, e esse erro não aconteceria na superclasse.O código do cliente depende do contrato publicado pela superclasse, pois não sabe com qual subclasse pode estar interagindo.
Como exemplo oposto, imagine que a superclasse tem uma pré-condição que diz que
i
não deve ser0
. Isso significa que nenhum cliente bem-comportado vai chamar oFoo
método com um0
argumento. Se você então implementar uma subclasse que pode manipular0
, nenhum dano é causado. Assim, você pode ampliar a pré-condição, mas não restringi-la.Considerações semelhantes se aplicam a pós-condições, apenas na direção oposta. Aqui, uma subclasse pode apertar uma pós-condição, mas não alargá-la.
Você pode ver alguns exemplos realistas de C# no meu artigo O PrincÃpio de Substituição de Liskov como um profunctor .
A violação do princÃpio de substituição de Liskov leva à execução incorreta do programa.
Aqui está um exemplo de tal violação: