Escrevi uma API de regras reutilizáveis, que resolve esse tipo de problema.
Me baseei num padrão chamado Specification.
Com essa API você consegue validar todas suas regras de negócio e só ao final tratar as exceções necessárias.
Vejamos o exemplo hipotético de uma classe Pessoa, a qual desejamos validar o nome, idade e sexo:
class Pessoa {
String nome;
int idade;
char sexo;
Pessoa(String nome, int idade, char sexo) {
this.nome = nome;
this.idade = idade;
this.sexo = sexo;
}
}
Aí implementamos a regra para validar o nome:
import br.com.staroski.rules.*;
// Especificação da regra que valida o nome de uma Pessoa
class Nome implements Specification<Pessoa> {
@Override
public void verify(Pessoa pessoa) throws UnattendedException {
if (!pessoa.nome.matches("[A-Z]{1}[a-z]+")) {
throw new UnattendedException("Nome precisa começar com letra maiuscula e ter pelo menos duas letras");
}
}
}
A regra para validar a idade:
import br.com.staroski.rules.*;
// Especificação da regra que valida a idade de Pessoa
class Idade implements Specification<Pessoa> {
@Override
public void verify(Pessoa pessoa) throws UnattendedException {
if (pessoa.idade < 0) {
throw new UnattendedException("Idade não pode ser negativa");
}
}
}
E a regra para validar o sexo:
import br.com.staroski.rules.*;
// Especificação da regra que valida o sexo de uma Pessoa
class Sexo implements Specification<Pessoa> {
@Override
public void verify(Pessoa pessoa) throws UnattendedException {
switch (pessoa.sexo) {
case 'M':
case 'F':
return;
default:
throw new UnattendedException("Sexo só pode ser 'M' ou 'F'");
}
}
}
Agora que as regras foram implementadas, segue um exemplo de como utilizá-las para validar as informações de um objeto do tipo Pessoa:
import br.com.staroski.rules.*;
public class Exemplo {
public static void main(String[] args) {
// instanciamos as regras a partir das especificações
Rule<Pessoa> nome = Rule.create(new Nome());
Rule<Pessoa> idade = Rule.create(new Idade());
Rule<Pessoa> sexo = Rule.create(new Sexo());
// criamos uma pessoa com nome, idade e sexo validos
Pessoa pessoa = new Pessoa("Fulano", 30, 'M');
// criamos uma regra só que corresponde às três regras: nome, idade e sexo
// e validamos com um único if
if (nome.and(idade).and(sexo).isSatisfiedBy(pessoa)) {
System.out.println("Teste 1");
System.out.println("O nome, idade e sexo da pessoa atendem as regras\n");
}
// criamos uma pessoa com nome, idade e sexo inválidos
pessoa = new Pessoa("FuLaNo", -1, 'S');
// criamos uma regra só que corresponde às três regras: nome, idade e sexo
// armazenamos essa regra numa variável
Rule<Pessoa> regra = nome.and(idade).and(sexo);
// assim, validamos as três regras, com um único if
if (regra.not().isSatisfiedBy(pessoa)) {
System.out.println("Teste 2");
System.out.println("A pessoa não atendeu as seguintes regras:");
// se a pessoa não atendeu às regras,
// usamos a variável declarada para obter os detalhes
for (String detalhe : regra.getDetails()) {
System.out.println(detalhe);
}
}
}
}