How to chain checks in java

前端 未结 2 669
难免孤独
难免孤独 2021-01-06 08:11

Consider a class like the following

public class MyClass {

    private Integer myField;
    private Result result;
    // more global variables

    public          


        
2条回答
  •  执念已碎
    2021-01-06 08:36

    When we think about validation, it is generally a Composite pattern. It broadly is depicted as:

    If THIS is valid, then do SOMETHING.

    And as you are imposing, you want to chain up multiple checkers in a chain to perform validation in their area, you can implement a Chain of Responsibility pattern.

    Consider this:

    You can have a Result Object, that can contain a message about failure as well as simple true/false.

    You can have a Validator Object, that does whatever validation is required and returns an instance of Result.

    public interface Result {  
        public boolean isOk();
        public String getMessage();
    }
    
    // We make it genric so that we can use it to validate
    // any type of Object that we want.
    public interface Validator {
        public Result validate(T value);
    }
    

    Now when you say that you want to validate 'X' using multiple checkers, you're imposing a Validation Rule that is nothing but a collection of Validator objects while being an instance of Validator itself. That being said, you can no more use the Result object to check the validation result of your rule. You will need a composite Result object that can keep the results as {Validator=Result}. Doesn't it look like an implementation of HashMap? Yes, because it is.

    Now you can implement your Rule and CompositeResult as:

    public class Rule extends ArrayList implements Validator {
    
        public Rule(Validator ... chain) {
            addAll(Arrays.asList(chain));
        }
    
        public Object validate(Object target) {
            CompositeResult result = new CompositeResult(size());
            for (Validator rule : this) {
                Result tempResult = rule.validate(value);
                if (!tempResult.isOk())
                    result.put(rule, tempResult);
            }
            return result;
        }
    }
    
    public class CompositeResult extends HashMap implements
            Result {
    
        private Integer appliedCount;
    
        public CompositeResult(Integer appliedCount) {
            this.appliedCount = appliedCount;
        }
    
        @Override
        public boolean isOk() {
            boolean isOk = true;
            for (Result r : values()) {
                isOk = r.isOk();
                if (!isOk)
                    break;
            }
            return isOk;
        }
    
        @Override
        public String getMessage() {
            return toString();
        }
    
        public Integer failCount() {
            return size();
        }
    
        public Integer passCount() {
            return appliedCount - size();
        }
    
    }
    

    And that's it! Now, to implement your checkers:

    public class Checker1 implements Validator {
        /* Implementation */
    }
    
    public class CheckerN implements Validator {
        /* Implementation */
    }
    

    And it's time to do the validation:

    Validator checkingRule = new Rule(new Checker1(), new CheckerN());
    CompositeResult result = checkingRule.validate(yourParameter);
    if (result.isOk()) 
        System.out.println("All validations passed");
    else
        System.out.println(result.getFailedCount() + " validations failed");
    

    Easy and neat.

    I have uploaded an example in my public repo for you to play around.

提交回复
热议问题