Criando classes de validação

5

Este é um follow-up de esta questão . Decidi implementar o que a resposta aceita sugere, no entanto, percebi que também precisava de métodos públicos individuais para cada membro que a entidade a ser validada tinha, portanto não é apenas validado como um todo, mas também seus membros como unidades separadas: p>

Isso é o que foi sugerido:

public interface Validable {
    public void setValidator(Validator validator);
    public void validate() throws ValidationException;
    public List<String> getMessages();
}

public interface Validator<T> {
    public boolean validate(T e);
    public List<String> getValidationMessages();
}

public class EventValidator implements Validator<Event> {
    public boolean validate(Event e) {
        // validate each member here, as well as the entity as a whole
        return isValid;
    }

    // etc...
}

Mas agora preciso de métodos públicos para cada membro do Event . O motivo é usar cada um desses métodos nos Event setters e métodos com um propósito semelhante, como adicionar itens a uma lista ou dicionário, inicializar dados, modificar dados, etc.

Então eu precisaria de algo como:

public class EventValidator implements Validator<Event> {
    // Validates the whole object
    public boolean validate(Event e) {
        // ...
    }

    public boolean validatePlayers() {
        // ...
    }

    public boolean validateCourts() {
        // ...
    }

    public boolean validateMatches() {
        // ...
    }
}

A primeira coisa que posso ver é transformar esse parâmetro Event e no método "main" validate(Event e) em uma variável de membro, para que o restante dos métodos possa acessá-los. Mas isso viola todo o ponto desse design, que foi dissociando a entidade do validador.

Qual seria o design mais adequado para atender às minhas necessidades? Eu não me importaria se tivesse que começar do zero e esquecer totalmente o design atual.

    
por dabadaba 23.04.2016 / 19:49
fonte

3 respostas

1

Acho que pode ajudar a perceber que o Validable e o Validator são interfaces relacionadas à validação de uma única entidade e que agora você está tentando forçar a validação de uma composição de entidades nesse design. Seu validador só deve validar o evento, não tente usá-lo para validar as regras para a criação do evento. Faça uma distinção entre o evento e as regras para criar o evento .

Depois de obter essa percepção, você tem muitas opções no futuro.

Parece que você está modelando uma partida de tênis. Nesse caso, um evento provavelmente deve ser criado por algum tipo de matchmaker. (Pode servir para você usar o padrão de construtor?) O que você está realmente querendo validar não é o evento , mas as etapas no processo de construir um evento . O design que você tem fará um excelente trabalho na validação de entidades individuais, mas agora você precisa validar as regras para compor essas entidades em um evento.

    
por 24.05.2016 / 14:47
fonte
0
public class EventValidator implements Validator<Event> { 
    // Validates the whole object 
        public boolean validate(Event e){ 
           return validatePlayers(e) && 
    validateCourts(e) && 
    validateMatches(e);
          // and so on....
        } 
        public boolean validatePlayers(Event e) {
            event.getPlayers() ...
            // ... 
        }
        public boolean validateCourts(Event e) { 
            event.getCourts() ...
             // ... 
        } 
        public boolean validateMatches(Event e) { 
            // ... 
         }
 }

Isso é o que eu estava sugerindo no meu comentário. Com todos os outros públicos, eles podem ser invocados individualmente para validacions singulares. Além disso, o método principal é o resultado de todos os outros. (Ou qualquer outra lógica de validação).

Quem sugeriu a você que essa estratégia foi realmente inteligente. A estratégia abaixo é a mesma sob a interface Comparator . Não se preocupe com esse acoplamento. É realmente um acoplamento suave.

Se você não quer ter nenhum tipo de acoplamento, então você precisa de um tipo personalizado para ser usado como parâmetro em vez de Evento. Vamos dizer Validável

Validable é uma interface que precisa ser implementada por qualquer entidade do seu candidato a ser validada.

Esta interface também tem 1 método isValid () . E toda classe que implementa essa interface é responsável por se validar. EventValidator apenas aciona uma cadeia de execução isValid () .

Mas essa abordagem precisa de um pouco de refrator. Eu postaria, mas levaria séculos para fazer isso no meu smartphone.

Espero que isso ajude.

.-.-.-.-.-

Nota : Se você tem tantas validações, na verdade, ter 20 métodos é um projeto muito ruim. Então sua escolha é: ter 20 validadores. Isso pode parecer muito código, mas é preferível ter 20 classes fazendo ações simples em uma classe simples fazendo 20 coisas diferentes. Minha classe faz apenas 1 coisa, mas funciona bem . Para que os X Validators deixem você reutilizar esse pequeno código em qualquer lugar do projeto. Além disso, está aberto a possíveis validações compostas (por composição ou herança)

    
por 23.04.2016 / 20:42
fonte
0

Este é um design alternativo onde várias validações de "etapas" podem ser chamadas separadamente:

== > IValidable.java < ==

import java.util.List;

public interface IValidable {
    public void setValidator(IValidator<Event> validator_);
    public void validate(String stepTag) throws ValidationException, UnknownStepTagException;
    public String getLastValidationMessage();
}

== > IValidator.java < ==

import java.util.List;

public interface IValidator<T> {
    public boolean validate(T e, String stepTag) throws UnknownStepTagException;
    public String getLastValidationMessage();
    public String getLastStepTag();
}

== > Event.java < ==

import java.util.List;

public class Event implements IValidable {

    public static final String VALIDABLE_STEP_PLAYERS="PLAYERS";
    public static final String VALIDABLE_STEP_COURTS="COURTS";
    public static final String VALIDABLE_STEP_MATCHES="MATCHES";

    private IValidator<Event> validator;
    private String lastValidationMessage;

    @Override
    public void setValidator(IValidator<Event> validator_) {
        this.validator = validator_;
    }

    @Override
    public void validate(String stepTag) throws ValidationException, UnknownStepTagException {
        if (!this.validator.validate(this,stepTag)){
            throw new ValidationException("WTF!");
        }
    }

    @Override
    public String getLastValidationMessage() {
        return this.lastValidationMessage;
    }

}

== > SimpleEventValidator.java < ==

public class SimpleEventValidator implements IValidator<Event> {

    private String lastValidationMessage ="";
    private String lastStepTag="";
    @Override
    public boolean validate(Event e, String stepTag) throws UnknownStepTagException {
        // based on the stepTag executed appropiate privateMethod
        // this example always returns false    
        this.lastStepTag=stepTag;
        return false;
    }

    @Override
    public String getLastValidationMessage() {
        return this.lastValidationMessage;
    }

    @Override
    public String getLastStepTag() {
        return this.lastStepTag;
    }

    private boolean validateThis(){
        return false;
    }

    private boolean validateThat(){
        return false;
    }       

}

== > UnknownStepTagException.java < ==

public class UnknownStepTagException extends Exception {

}

== > ValidationException.java < ==

public class ValidationException extends Exception {
    public ValidationException(String message) {
        super(message);
    }

    private static final long serialVersionUID = 1L;
}

== > Test.java < ==

import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main (String args[]){
        Event e = new Event();
        IValidator<Event> v = new SimpleEventValidator();
        e.setValidator(v);
        List<String> messages = new ArrayList<String>();
        // set other thins to e like
        // e.setPlayers(player1,player2,player3)
        // e.setNumberOfMatches(3);
        // etc
        try {
            e.validate(Event.VALIDABLE_STEP_COURTS);
            messages.add(e.getLastValidationMessage());
            e.validate(Event.VALIDABLE_STEP_MATCHES);
            messages.add(e.getLastValidationMessage());
            e.validate(Event.VALIDABLE_STEP_PLAYERS);
            messages.add(e.getLastValidationMessage());
        } catch (ValidationException e1) {
            messages.add(e.getLastValidationMessage());
            System.out.println("Your event doesn't comply with the fedaration regulations for the following reasons: ");
            for (String s:messages){
                System.out.println(s);
            }
        } catch (UnknownStepTagException e2) {
            System.out.println("Unknown validation step "+v.getLastStepTag());
        }
    }
}

===============

    
por 22.08.2016 / 20:07
fonte