O que é uma classe coesa?
Uma classe coesa é aquela que tem apenas uma responsabilidade.
Classes coesas são menores, mais organizadas, fáceis de manter e reutilizar.
Exemplo de classe com baixa coesão
class CalculadoraDeSalario {
calcula(funcionario) {
if (funcionario.cargo === "DESENVOLVEDOR") {
return this.dezOuVintePorcento(funcionario);
}
if (funcionario.cargo === "DBA" || funcionario.cargo === "TESTER") {
return this.quinzeOuVinteCincoPorcento(funcionario);
}
throw new Error("Funcionário inválido");
}
dezOuVintePorcento(funcionario) {
if (funcionario.salarioBase > 3000) {
return funcionario.salarioBase * 0.8;
}
return funcionario.salarioBase * 0.9;
}
quinzeOuVinteCincoPorcento(funcionario) {
if (funcionario.salarioBase > 2000) {
return funcionario.salarioBase * 0.75;
}
return funcionario.salarioBase * 0.85;
}
}
Problemas dessa classe
- A classe precisa saber todos os cargos.
- Muitos ifs → sempre que surgir um novo cargo, a classe precisa ser alterada.
- As regras de cálculo não podem ser reutilizadas facilmente.
- A classe tem mais de uma responsabilidade (decidir o cargo + calcular o salário).
Ou seja, baixa coesão e alto acoplamento.
O ideal seria cada regra de cálculo estar em uma classe separada. Isso aumenta a coesão e facilita reutilização e manutenção.
Por que essa classe é difícil de reutilizar?
Imagine que você queira reutilizar apenas a regra dezOuVintePorcento() em outro lugar do sistema.
Você não consegue usar só o método, porque ele está dentro da classe CalculadoraDeSalario.
Então você é obrigado a:
- Instanciar a classe
- Criar um objeto funcionário
- Passar o funcionário
- Só então usar o método
Ou seja, para reutilizar uma regra de cálculo, você precisa levar a classe inteira junto.
Isso é um sinal claro de baixa coesão, porque a classe está fazendo coisas demais.
Exemplo de classe refatorada com alta coesão
class Cargo {
calculaSalario(salarioBase) {
throw new Error("Método deve ser implementado pela subclasse");
}
}
class Desenvolvedor extends Cargo {
calculaSalario(salarioBase) {
return salarioBase > 3000
? salarioBase * 0.8
: salarioBase * 0.9;
}
}
class Dba extends Cargo {
calculaSalario(salarioBase) {
return salarioBase > 2000
? salarioBase * 0.75
: salarioBase * 0.85;
}
}
class Tester extends Cargo {
calculaSalario(salarioBase) {
return salarioBase > 2000
? salarioBase * 0.75
: salarioBase * 0.85;
}
}
const RegrasPorCargo = {
DESENVOLVEDOR: new Desenvolvedor(),
DBA: new Dba(),
TESTER: new Tester()
};
class CalculadoraDeSalarioRefatorada {
calcula(funcionario) {
const regra = RegrasPorCargo[funcionario.cargo];
if (!regra) {
throw new Error("Funcionário inválido");
}
return regra.calculaSalario(funcionario.salarioBase);
}
}
const funcionario2 = {
cargo: "DESENVOLVEDOR",
salarioBase: 3500
};
const calculadora2 = new CalculadoraDeSalarioRefatorada();
console.log(calculadora2.calcula(funcionario2));
Primeiro passo para entender a refatoração
Antes da refatoração, a classe CalculadoraDeSalario mudava por dois motivos:
- Quando surgia um novo cargo
- Quando surgia uma nova regra de cálculo
Ou seja, a classe tinha mais de um motivo para mudar, o que quebra o SRP (Single Responsibility Principle).
Se observarmos os métodos de cálculo, mesmo sendo diferentes, todos têm o mesmo formato:
- Recebem o salário
- Aplicam uma regra
- Retornam o salário calculado
Ou seja, todos seguem a mesma abstração.
Então a ideia da refatoração é criar uma classe para cada regra de cálculo, todas com o mesmo método calculaSalario().
- O que ganhamos com isso?
- Cada regra fica isolada
- Uma mudança em uma regra não afeta as outras
- As classes ficam menores
- As classes ficam mais coesas
- O sistema fica mais fácil de manter
- Podemos adicionar novos cargos sem alterar código existente
Agora cada classe tem apenas um motivo para mudar: a sua própria regra de cálculo.
Por que não separar em pequenos métodos?
Se separamos um método grande em pequenos métodos não teremos reuso isolado.
Referência
Este exemplo e a ideia de refatoração foram inspirados no livro: Orientação a Objetos e SOLID para Ninjas - Projetando classes flexíveis - MAURÍCIO ANICHE
Top comments (0)