Search code examples
javadesign-patternssolid-principlesdesign-principles

How can remove conditional statements while adding the common responsibility to the class?


I am building up a validation engine. There are common rules, which I have consolidated in a parent interface static method.

    public interface EmployeeValidator {
        Predicate<Employee> build(Employee employee);

        static Predicate<Employee> getCommonRules(Employee employee) {
            return validateAge().and(validateGenger());
        }

        private static Predicate<Employee> validateAge() {
            ...
        }

        private static Predicate<Employee> validateGenger() {
            ...
        }
    }

Now, the class that implements this interface will add more validation rules to it. There will be multiple implementations of EmployeeValidator

    class BackOfficeStaffValidator implements EmployeeValidator {

        @Override
        public Predicate<Employee> build(Employee employee) {
            return EmployeeValidator.getCommonRules(employee).and(validationsOnDirectReports());
        }

        private Predicate<Employee> validationsOnDirectReports() {
            ...
        }
    }

But the problem with this approach, at the client. I need conditional statements or switch case to select the proper implementation.

    Employee employee = ...;

    if(employee.staffType() == StaffType.TECHNICAL) {
        Predicate<Employee> validator = new TechnicalStaffValidator().build(employee);
    } else if(employee.staffType() == StaffType.BACK_OFFICE) {
        Predicate<Employee> validator = new BackOfficeStaffValidator().build(employee);
    }

Is there a way to improve my current design? If this approach is not moving in the right direction then feel free to suggest an alternate approach.


Solution

  • You could add an method like 'isReponsibleFor(StaffType)' to your EmployeeValidator interface. Each validator can now check, if it is response for the given type.

    Add all your validators to a list and iterate over the list of validators. If your validator is responsible for the given type, call the build method. You can also add checks, so there's only one validator per type and so on.

    List<EmployeeValidator> validators = getListOfValidators();
    
    for (EmployeeValidator validator : validators) {
       if (validator.isReponsibleFor(employee.staffType()) {
          Predicate<Employee> validator = validator.build(employee);
          // uses the first validator only
          break;
       }
    }