Loading repository data…
Loading repository data…
wesloy / repository
Este projeto tem como intuito aplicar os princípios SOLID utilizando C#, transformando conceitos em algo mais concreto. Este projeto também será um guia para projetos futuros, independente da linguagem a ser utilizada
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
Este projeto tem como intuito aplicar os princípios SOLID utilizando C#, transformando conceitos em algo mais concreto. Este projeto também será um guia para projetos futuros, independente da linguagem a ser utilizada.
Observação: toda palavra seguida de asterisco, possui uma breve descrição na penúltima sessão deste Redme, sessão Glossário, com o objetivo de elucidar quaisquer dúvidas sobre a utilização do termo no contexto deste artigo. Exemplo: Glossário*
Esse termo é um acrônimo:
SOLID não é um Desgner Patterns é na verdade um conjunto de princípios* que tem como objetivo a construção de sistemas mais compreensivos, flexíveis e sustentáveis.
O que será facilmente identificado ao se ler este artigo é que os princípios SOLID são inter-relacionados e diretamente dependentes um do outro, em alguns casos são sutís diferenças que devem ser observadas para conseguir visualizar o princípio que você está buscanco analisar. Em sintese, uma excelente aplicação do SOLID em seu código fará com que 2, 3 ou até mais princípios estejam presentes em apenas uma entidade*.
O SRP tem como objetivo fazer com que qualquer entidade tenha apenas uma responsabilidade.
Em outras palavras uma entidade deve ter apenas uma razão de existir. Assim será evidata as "God Class", onde uma única classe realiza diversos processos diferentes. Utilizar este princípio será base para todos os demais do SOLID.
public class Funcionario
{
void PrepararAlimentos();
void Cozinhar();
void MontarPrato();
void AnotarPedido();
void ServirMesa();
void FinalizarConta();
void ReceberPagamento();
}
Até aqui no exemplo temos uma classe que realiza todas as funções fundamentais existentes em uma lanchonete. Continuar com o código assim irá gerar muitas "gambiarras", em manutenções e dificultará a análise para correções de .
public class Cozinheiro
{
void PrepararAlimentos();
void Cozinhar();
void MontarPrato();
}
public class Garcom
{
void AnotarPedido();
void ServirMesa();
}
public class Caixa
{
void FinalizarConta();
void ReceberPagamento();
}
Agora, observamos classes bem segregadas com os métodos específicos. Refatorando a God Class temos um código mais compreensivo, isolado e de fácil identificação de bugs e rápida solução dos mesmos.
Se houver dificuldade para nomear uma entidade, com um nome totalmente descritivo e ao mesmo tempo curto/breve. É um indício de que a entidade tem mais do que uma responsabilidade.
O OCP dita que uma entidade está aberta para extensão e fechada para modificação.
De modo simples, a entidade está fechada para ser alterada. Muitas vezes, alguns programadores se vêem motivados a modificar uma entidade e colocar um "if" para resolver uma nova situação nova que surja. Justificando que é apenas uma condição, mas esquecendo que qualquer que seja a outra entidade que possa herdar desta também será afetada e ainda mais, não levando em conta que em futuro breve ou não, outras condicionais poderão surgir, fazendo com que o código fique poluído e difícil de ser entendido e dada a devida manutenção.
E ela está aberta para ser extendida, quando outras entidades podem usá-la por herança e adicionar novas funcionalidades.
Mudar é sempre um risco, extender é garantir que o que estava implementado continue a funcionar e a nova regra de negócio será apenas para uma extensão de algo que já está funcional.
public interface IAutomovel
{
void Move();
void Buzina();
}
public class Entregador
{
public void Dirigir(IAutomovel automovel)
{
automovel.Move();
}
public void AvisarChegada(IAutomovel automovel)
{
automovel.Buzina();
}
}
Neste exemplo o entregador não está limitado a um tipo de veículo, bem como a interface IAutomovel pode ser usada como extensão para diversos outros cenários, como: carros específicos e/ou outros tipos de condutores (piloto, motorista de ônibus, motociclista, etc).
Se o código possui "Ifs" com a intenção de validar todas as variáveis externas que surgiram é um alerta de que a OCP deve ser olhado com carinho.
LSP prega que uma entidade base poderá ser substituída por uma entidade derivada, sem prejuízo para o software e que as entidades derivadas nunca devem infligir as definições/comportamentos da entidade base.
O LSP, tem foco nas abstrações e para que seu princípio seja obedecido, refatora-se a abstração base para um nível que realmente possa atender de forma genérica, sem obrigar que as entidades derivadas façam testes lógicos ("Ifs") para evitar exceções. Em outras palavras, nos fornece uma forma de saber se uma herança está implementada em um nível correto ou não. Através do uso de polimorfismo, ao usar um método ou propriedade, seja da classe base ou da classe especialista, o resultado sempre deve estar correto sem qualquer alteração.
public class Integrador
{
public void EnviaEmail(string conteudo)
{
// Obtem o conteudo...
// Envia para alguem
}
}
public class Sistema
{
public void Integra()
{
Integrador integrador = new Integrador();
integrador.EnviaEmail("Conteudo!");
}
}
Caso precisemos adicionar uma integração via API, vamos precisar adicionar mais um metodo no nosso integrador e provavelmente um if no nosso metodo Sistema.Integra(). Alem disso a nossa classe Sistema precisa "entender" que tipo de integração ele vai fazer(API ou Email).
Para evitar isso, podemos, mais uma vez, usar interfaces!
public interface IIntegrador
{
void Envia(string conteudo);
}
public class IntegradorEmail : IIntegrador
{
public void Envia(string conteudo)
{
// Faz lógica de EMAIL
}
}
public class IntegradorAPI : IIntegrador
{
public void Envia(string conteudo)
{
// Faz a lógica de API
}
}
public class Sistema
{
public void Integra(IIntegrador integrador)
{
integrador.Envia("Conteudo!");
}
}
Agora o Sistema não precisa saber se o envio do e-mail é por meio de uma API, SMTP ou qualquer outra tecnologia.
Se o código possui "Ifs" com a intenção de validar todas as variáveis externas que surgiram é um alerta de que a LSP deve ser olhado com carinho. Quanto a essa dica a diferença existente entre o LSP e OCP é que o LSP foca exclusivamente na abstração.
ISP tem como princípio que os clientes* que implementam uma interface não devem ser obrigados a implementar uma ação/método que não utiliza.
O ISP é a aplicação dos princípios SRP, OCP e LSP, direcionandos para interfaces.
public interface IVeiculo
{
void Abastecer(string combustivel);
void FecharPortas();
void LevantarTripe();
void Mover();
void Estacionar();
}
public class Carro : IVeiculo
{
public void Abastecer(string combustivel) { }
public void FecharPortas() { }
public void LevantarTripe()
{
throw new System.Exception("Não tem tripé!");
}
public void Mover() { }
public void Estacionar() { }
}
public class Moto : IVeiculo
{
public void Abastecer(string combustivel) { }
public void FecharPortas()
{
throw new System.Exception("Não tem portas!");
}
public void LevantarTripe() { }
public void Mover() { }
public void Estacionar() { }
}
Até o presente momento, conseguimos notar que tanto a classe Carro, como a classe Moto foram obrigados a implementar métodos que não podem executar.
Uma das abordagens corretas deveria ser, conforme abaixo.
public interface IVeiculo
{
void Abastecer(string combustivel);
void Mover();
void Estacionar();
}
public interface ICarro
{
void FecharPortas();
}
public interface IMoto
{
void LevantarTripe();
}
public class Carro : IVeiculo, ICarro
{
public void Abastecer(string combustivel) { }
public void Mover() { }
public void Estacionar() { }
public void FecharPortas() { }
}
public class Carro : IVeiculo, IMoto
{
public void Abastecer(string combustivel) { }
public void Mover() { }
public void Estacionar() { }
public void LevantarTripe() { }
}
Agora chegamos ao nível correto de segregação das interfaces e desobrigamos a implementação a tratar com excessões ações que a interface exigia dela e a implementação como cliente não poderia executar.
Se um cliente precisar "passar por alto" algum método da interface e/ou a atualização da interface* provoque este mesmo efeito em outras classes que já estão implementadas é sinal de que o ISP está sendo infligido.
Observação: alterar uma interface, para incluir um novo método é extremamente perigoso, visto que pode quebrar o software de diversas formas diferentes. Isto apenas se deve ser feito no caso específico de que todas as implementações necessitem deste novo método.
DIP determina que módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações e abstrações não devem depender de detalhes. Detalhes devem depender de abstrações.
O DIP em poucas palavras diz "Dependa de uma abstração e não de uma implementação".
Olhando para as vantagens descritas abaixo, nota-se que o DIP é, por assim dizer, o mais importante de todos os princípios. Já que sua aplic