propriedades do objeto.IMPORTANTE: os calculos aqui estao bem simplificados, na vida real a tributacao e bem mais complexa...Um desenvolvedor pode entao criar a classe Taxi, herdando de Carro, para fazer o calculo de imposto na venda de veiculos para transporte comercial de passageiros, aproveitando assim outros metodos que a classe Carro tenha e que sejam comum para o sistema (o que nao deveria ser o fator para a decisao em se utilizar heranca). Taxistas tem uma serie de isencoes de impostos para fomentar sua profissao. Este desenvolvedor entao sobrescreve o metodo CalcularValorImposto zerando o valor dos impostos que o taxista e desobrigado a pagar.A principio nao existem problemas nessa implementacao pois eu consigo fazer o calculo do imposto para compra de carros e de taxis chamando o metodo CalcularValorImposto da respectiva instancia. Mas ha um problema. Veja que no nosso cliente, que no codigo de exemplo e uma classe de teste de unidade, quando fazemos a substituicao da dependencia Carro no metodo DeveCalcularValorImposto por uma instancia de Taxi, a funcionalidade quebra.Este exemplo de codigo, neste contexto, nao atende o principio de Liskov. A pos condicao na chamada do metodo CalcularValorImposto quando e feita na classe Carro e ter todos os valores de impostos calculados (as propriedades ICMS, IPI, PIS e COFINS). Ja a pos condicao na chamada do mesmo metodo para a classe Taxi e ter algum dos valores dos impostos calculados dada a isencao. Note que a pos condicao da classe Taxi e mais "fraca", menos restritiva. Ter uma pos condicao mais fraca na subclasse e um dos indicios de violacao do principio de Liskov. Outro sinal seria se as pre condicoes da classe filha fossem mais restritivas.using System;using Microsoft.VisualStudio.TestTools.UnitTesting;namespace LiskovNok{ public class Carro { protected const double ALIQUOTA_ICMS = 12; protected const double ALIQUOTA_IPI = 18; protected const double ALIQUOTA_PIS = 1.65; protected const double ALIQUOTA_COFINS = 7.6; public double ICMS { get; set; } public double IPI { get; set; } public double PIS { get; set; } public double COFINS { get; set; } public virtual void CalcularValorImposto(double valorBruto) { ICMS = valorBruto * ALIQUOTA_ICMS / 100; IPI = valorBruto * ALIQUOTA_IPI / 100; PIS = valorBruto * ALIQUOTA_PIS / 100; COFINS = valorBruto * ALIQUOTA_COFINS / 100; } public double Imposto { get { return ICMS + IPI + PIS + COFINS; } } } public class Taxi : Carro { public override void CalcularValorImposto(double valorBruto) { base.CalcularValorImposto(valorBruto); ICMS = 0; PIS = 0; } } [TestClass] public class UnitTest1 { [TestMethod] public void DeveCalcularValorImpostoCarro() { DeveCalcularValorImposto(new Carro()); } [TestMethod] public void DeveCalcularValorImpostoTaxi() { DeveCalcularValorImposto(new Taxi()); } private void DeveCalcularValorImposto(Carro sut) { sut.CalcularValorImposto(45000); Assert.AreEqual(17662.5, sut.Imposto); } }}Agora vamos ver um exemplo onde a regra de Liskov e atendida. Vou mostrar ainda utilizando as classes Carro e Taxi mas com um contexto diferente.Na listagem de codigo seguinte, vemos um sistema que faz o calculo de estimativa de distancia entre dois pontos no mapa para um sistema estilo Waze. A classe Carro faz isso atraves do metodo CalcularEstimativas onde recebe dois pontos (objetos da estrutura Coordenada que traz a