Com o tempo, eu pude entender duas partes do SOLID - o "S" e o "O".
“O” - eu aprendi o Princípio Aberto Fechado com a ajuda de Herança e Padrão de Estratégia.
"S" - aprendi o princípio de responsabilidade única enquanto aprendia o ORM (a lógica da persistência é retirada dos objetos do domínio).
De maneira semelhante, quais são as melhores regiões / tarefas para aprender outras partes do SOLID (o "L", "I" e "D")?
Referências
Respostas:
Eu estava no seu lugar há alguns meses, até encontrar um artigo muito útil.
Cada princípio é bem explicado com situações do mundo real que cada desenvolvedor de software pode enfrentar em seus projetos. Estou cortando aqui e apontando a referência - Desenvolvimento de Software SOLID, um passo de cada vez .
Como apontado nos comentários, há outra leitura muito boa do pdf - o SOLID Software Development de Pablo .
Além disso, existem alguns bons livros que descrevem os princípios do SOLID em mais detalhes - Bom livro sobre desenvolvimento de software do SOLID .
Edite e comentários de um breve resumo para cada princípio:
"S" - Princípio de Responsabilidade Única é orientado pelas necessidades da empresa para permitir mudanças. “Um único motivo para mudar” ajuda a entender quais conceitos logicamente separados devem ser agrupados considerando o conceito e o contexto de negócios, em vez do conceito técnico.
In another words
, aprendi que cada classe deve ter uma única responsabilidade. A responsabilidade é apenas realizar a tarefa atribuída“O” - eu aprendi o Princípio Aberto Fechado e comecei a "preferir composição sobre herança" e, como tal, preferindo classes que não têm métodos virtuais e são possivelmente seladas, mas dependem de abstrações para sua extensão.
"L" - Aprendi o Princípio de Substituição de Liskov com a ajuda do padrão Repository para gerenciar o acesso a dados.
Como um recurso útil do CodePlex foi mencionado nos comentários, é incluída referência ao SOLID por exemplo
fonte
(I) a segregação da interface e (D) a inversão da dependência podem ser aprendidas através de testes de unidade e zombaria. Se as classes criarem suas próprias dependências, você não poderá criar bons testes de unidade. Se eles dependem de uma interface muito ampla (ou nenhuma interface), não é muito óbvio o que precisa ser ridicularizado para fazer seus testes de unidade.
fonte
O Princípio de Substituição de Liskov basicamente não permite que você use demais a herança da implementação: você nunca deve usar a herança apenas para reutilizar o código (existe composição para isso)! Ao aderir ao LSP, você pode ter certeza de que realmente existe um "é um relacionamento" entre sua superclasse e sua subclasse.
O que diz é que suas subclasses devem implementar todos os métodos da subclasse de maneira semelhante à implementação dos métodos na subclasse. Você nunca deve substituir um método pela implementação do NOP ou retornar nulo quando o supertipo lança uma exceção; declarado nos termos Design por contrato, você deve respeitar o contrato do método da superclasse ao substituir um método. Uma maneira de se defender contra a quebra desse princípio é nunca substituir um método implementado; em vez disso, extraia uma interface e implemente essa interface nas duas classes.
Princípio de Segregação de Interface , Princípio de Responsabilidade Única e Princípio de Alta Coesão do GRASP estão de alguma forma relacionados; eles se referem ao fato de que uma entidade deve ser responsável por apenas uma coisa, para que haja apenas um motivo para a mudança, para que a mudança seja feita com muita facilidade.
Na verdade, ele diz que se uma classe implementa uma interface, deve implementar e usar todos os métodos dessa interface. Se houver métodos que não são necessários nessa classe específica, a interface não será boa e deverá ser dividida em duas interfaces, uma que possua apenas os métodos necessários para a classe original. Isso pode ser considerado a partir de um ponto de vista, que se relaciona ao princípio anterior pelo fato de ele não permitir que você crie interfaces grandes para que sua implementação possa quebrar o LSP.
Você pode ver a inversão de dependência no padrão de fábrica; aqui, o componente de alto nível (o cliente) e o componente de baixo nível (instância individual a ser criada) dependem da abstração(a interface). Uma maneira de aplicá-lo em uma arquitetura em camadas: você não deve definir uma interface para uma camada na camada implementada, mas no módulo chamado. Por exemplo, a API para a camada de fonte de dados não deve ser gravada na camada de fonte de dados, mas na camada de lógica de negócios, onde é necessário chamar. Dessa maneira, a camada da fonte de dados herda / depende do comportamento definido na lógica de negócios (portanto, a inversão) e não vice-versa (como seria normalmente). Isso fornece flexibilidade no design, permitindo que a lógica de negócios funcione sem nenhuma alteração de código, com outra fonte de dados totalmente diferente.
fonte