Você pode explicar o Princípio de Substituição de Liskov (O 'L' de SOLID) com um bom exemplo C # cobrindo todos os aspectos do princípio de uma forma simplificada? Se for realmente possível.
c#
.net
oop
solid-principles
liskov-substitution-principle
pencilCake
fonte
fonte
Respostas:
(Esta resposta foi reescrita em 13/05/2013, leia a discussão na parte inferior dos comentários)
LSP trata de seguir o contrato da classe base.
Você pode, por exemplo, não lançar novas exceções nas subclasses, pois aquele que usa a classe base não esperaria isso. O mesmo é válido se a classe base lançar
ArgumentNullException
se um argumento estiver faltando e a subclasse permitir que o argumento seja nulo, também uma violação do LSP.Aqui está um exemplo de uma estrutura de classe que viola o LSP:
E o código de chamada
Como você pode ver, existem dois exemplos de patos. Um pato orgânico e um pato elétrico. O pato elétrico só pode nadar se estiver ligado. Isso quebra o princípio LSP, uma vez que deve ser ativado para poder nadar, pois
IsSwimming
(que também faz parte do contrato) não será definido como na classe base.Claro, você pode resolvê-lo fazendo algo assim
Mas isso quebraria o princípio Aberto / Fechado e tem que ser implementado em todos os lugares (e portanto ainda gera código instável).
A solução adequada seria ligar automaticamente o pato no
Swim
método e, ao fazer isso, fazer com que o pato elétrico se comporte exatamente como definido pelaIDuck
interfaceAtualizar
Alguém adicionou um comentário e o removeu. Tinha um ponto válido que eu gostaria de abordar:
A solução com ativar o pato dentro do
Swim
método pode ter efeitos colaterais ao trabalhar com a implementação real (ElectricDuck
). Mas isso pode ser resolvido usando uma implementação de interface explícita . imho é mais provável que você tenha problemas ao NÃO ligá-lo,Swim
pois é esperado que ele nade ao usar aIDuck
interfaceAtualização 2
Reformulei algumas partes para ficar mais claro.
fonte
if duck is ElectricDuck
parte. Tive um seminário sobre SOLID na quinta-feira passada :)as
palavra - chave, o que realmente os salva de muitas verificações de tipo. Estou pensando algo como o seguinte:if var electricDuck = duck as ElectricDuck; if(electricDuck != null) electricDuck.TurnOn();
if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program (e.g., correctness).
LSP uma abordagem prática
Em todos os lugares que procuro por exemplos de C # do LSP, as pessoas usaram classes e interfaces imaginárias. Aqui está a implementação prática do LSP que implementei em um de nossos sistemas.
Cenário: suponha que temos 3 bancos de dados (clientes hipotecários, clientes de contas correntes e clientes de contas poupança) que fornecem dados do cliente e precisamos dos detalhes do cliente para o sobrenome do cliente fornecido. Agora podemos obter mais de 1 detalhe do cliente desses 3 bancos de dados com o sobrenome fornecido.
Implementação:
CAMADA DE MODELO DE NEGÓCIO:
CAMADA DE ACESSO DE DADOS:
A interface acima é implementada pela classe abstrata
Esta classe abstrata tem um método comum "GetDetails" para todos os 3 bancos de dados que é estendido por cada uma das classes de banco de dados conforme mostrado abaixo
ACESSO A DADOS DO CLIENTE DE HIPOTECA:
ACESSO DE DADOS DO CLIENTE DA CONTA ATUAL:
ACESSO A DADOS DO CLIENTE NA CONTA DE ECONOMIA:
Uma vez que essas 3 classes de acesso a dados são definidas, agora chamamos nossa atenção para o cliente. Na camada Business, temos a classe CustomerServiceManager que retorna os detalhes do cliente para seus clientes.
CAMADA DE NEGÓCIOS:
Não mostrei a injeção de dependência para mantê-la simples, pois já está ficando complicada.
Agora, se tivermos um novo banco de dados de detalhes do cliente, podemos simplesmente adicionar uma nova classe que estende BaseDataAccess e fornece seu objeto de banco de dados.
Claro, precisamos de procedimentos armazenados idênticos em todos os bancos de dados participantes.
Por fim, o cliente da
CustomerServiceManager
classe só chamará o método GetCustomerDetails, passará o lastName e não se preocupará com como e de onde os dados estão vindo.Espero que isso lhe dê uma abordagem prática para entender o LSP.
fonte
Aqui está o código para aplicar o Princípio do Substituto de Liskov.
LSV afirma: "As classes derivadas devem ser substituíveis por suas classes básicas (ou interfaces)" & "Métodos que usam referências a classes básicas (ou interfaces) devem ser capazes de usar métodos das classes derivadas sem saber sobre isso ou sem conhecer os detalhes . "
fonte