Single Responsibility Principle (S) - PauloGustavo72/solid GitHub Wiki

Single Responsibility Principle (S)

Esse princípio diz que nossas classes devem ter responsablidades únicas e somente um motivo para mudar. Nossa classe dever ser coesa. Exemplo de uma classe ruim que pode ser aplicado esse padrão:

public class CalculadoraDeSalario {


    public double calcula(Funcionario funcionario) {
        if(DESENVOLVEDOR.equals(funcionario.getCargo())) {
            return dezOuVintePorcento(funcionario);
        }

        if(DBA.equals(funcionario.getCargo()) || TESTER.equals(funcionario.getCargo())) {
            return quinzeOuVinteCincoPorcento(funcionario);
        }

        throw new RuntimeException("funcionario invalido");
    }

    private double dezOuVintePorcento(Funcionario funcionario) {
        if(funcionario.getSalarioBase() > 3000.0) {
            return funcionario.getSalarioBase() * 0.8;
        }
        else {
            return funcionario.getSalarioBase() * 0.9;
        }
    }

    private double quinzeOuVinteCincoPorcento(Funcionario funcionario) {
        if(funcionario.getSalarioBase() > 2000.0) {
            return funcionario.getSalarioBase() * 0.75;
        }
        else {
            return funcionario.getSalarioBase() * 0.85;
        }
    }

}

Uma possível solução para esse problema seria criar uma interface(RegraDeCalculo) que possua o método calcula(Funcionario funcionario) e duas outras classe que implementam ela como mostrado abaixo:

public class DezOuVintePorCento implements RegraDeCalculo {

    public double calcula(Funcionario funcionário);
            if(funcionario.getSalarioBase() > 3000.0) {
                return funcionario.getSalarioBase() * 0.8;
        }
        else {
            return funcionario.getSalarioBase() * 0.9;
        }
 }
 
 public class QuinzeOuVinteECincoPorCento implements RegraDeCalculo  {
    public double calcula(Funcionario funcionario) {
        if(funcionario.getSalarioBase() > 2000.0) {
            return funcionario.getSalarioBase() * 0.75;
        }
        else {
            return funcionario.getSalarioBase() * 0.85;
        }
    }

}

Assim quebramos as responsabilidades e essas novas classes só possui uma única responsabilidade e somente um motivo para mudar(caso mude a regra de quinzeOuVintePorCento, ou DezOuVintePorCento).

Devemos também passar um funcionário como parâmetro no Enum (Cargo), conforme a imagem abaixo:

public enum Cargo {
   DESENVOLVEDOR(new DezOuVintePorCento()),
   DBA(new DezOuVintePorCento()),
   TESTER(new QuinzeOuVinteECincoPorCento());
   
   private RegraDeCalcula regra;
   Cargo(RegraDeCalculo regra)  {
       this.regra = regra;
   }
   public RegraDeCalculo getRegra()  {
       return regra;
   }
}

Com isso obrigamos o desenvolvedor a cada novo cargo criado, passar como argumento um tipo de cálculo. A classe que calcula o salário baseado na regra fica da seguinte forma:

public double calcula(Funcionario funcionario)  {
    return funcionario.getCargo().getRegra().calcula(funcionario);`
}

Ou simplificando mais ainda:

public double  calcula(Funcionario funcionario)  {
     return funcionario.calculaSalario();
}

E o método calculaSalario na classe Funcionario assim:

public double calculaSalario()  {
    return  cargo.getRegra().calcula(this);
}
⚠️ **GitHub.com Fallback** ⚠️