3
respostas

Chain of Responsability também pode ser aplicada quando há mais de uma condição válida?

Estou implementando um validador de campos de formulário que submete o valor passado em cada campo a um conjunto de regras (e.g. obrigatório, maior que x, menor que y).

Achei o problema similar ao que é resolvido com o padrão Chain of Responsability, entretanto há uma diferença importante: durante a validação, várias - e não apenas uma - regra pode ser aplicada.

Por conta disso, acabei implementando a solução de outra forma. Segue abaixo parte do código para avaliação.

Gostaria de saber se essa mudança descaracteriza o problema resolvido pelo padrão e, caso sim, existe outro padrão de projeto para esse tipo de problema?

A interface que representa uma regra.

public interface Regra {    
    public Violacao validar(Componente campo, String valor);
}

A implementação da regra de preenchimento obrigatório.

public class PreenchimentoObrigatorio implements Regra {

    public static final String CHAVE_VIOLACAO = "preenchimento.obrigatorio";

    @Override
    public Violacao validar(Componente campo, String valor) {
        if (campo.getColunaNotNull())
            if (valor.isEmpty())
                return new Violacao(CHAVE_VIOLACAO, campo.getHtmlId());
        return null;
    }
}

Classe que representa o validador.

public class ValidadorRegistro {

    List<Regra> regras;

    Map<String, Mensagem> violacoes = new HashMap<>();

    public ValidadorRegistro() {
        regras = Arrays.asList(new PreenchimentoObrigatorio());
    }

    public List<Mensagem> validar(List<Componente> campos, Map<String, TypedValue> valor) {
        if (!regras.isEmpty())
            campos.forEach(campo -> {
                if (valor.get(campo.getHtmlId()) != null && valor.get(campo.getHtmlId()).getValue() != null) {
                    regras.forEach(regra -> {
                        adicionarViolacao(regra.validar(campo, valor.get(campo.getHtmlId()).getValue().toString()));
                    });
                }
            });
        return new ArrayList<Mensagem>(violacoes.values());
    }
    ...
}
3 respostas

Oi Rafael,

Primeiramente quero dizer que gostei muito da sua solução, achei bem elegante, parabéns!

Acho que esta solução se encaixaria mais num Strategy do que num ChainOfResponsability pois você quer executar validações e cada uma terá sua própria forma de validar.

Abraço!

Oi Joviane,

Obrigado pelo feedback. A solução final acabou ficando um pouco diferente. Depois de ler sobre o padrão Decorator acabei alterando um pouco a implementação.

Vendo exemplos de aplicação dos padrões Strategy, Chain of Responsability e Decorator tudo parece muito claro, mas quando nos deparamos com os problemas sempre é desafiador aplicar o padrão certo.

No meu caso, acabei assumindo que minha solução não era uma aplicação de Chain of Responsability porque cada validador de fato faz sua validação e em seguida entrega a entrada para o próximo validador fazer sua parte. Por conta disso, implementei o padrão Decorator.

Oi Rafael sobre sua pergunta: Chain of Responsability também pode ser aplicada quando há mais de uma condição válida? Não só pode como deve inclusive na intenção do padrão temos:

  • Evitar o acoplamento de um remetente de uma solicitação ao seu receptor, ao dar a mais de um objeto a oportunidade de tratar a solicitação.

Ou seja o que eu sei quando passo uma solicitação para a cadeia é que alguém(pelo menos um) vai tratar não sei quem, pode ser que um trate, dois tratem, ou todos tratem.

Eu posso configurar essa cadeia com múltiplas responsabilidades mas que dado uma solicitação mais de uma atenda, com certeza.

Espero ter ajudado e bons estudos.