Currently, I try to design some things with OO principles in mind. So let's say, before processing user input, I need to validate it. According to OO, a separate Validator class would be the correct way. This would look as follows:
public class Validator{
public void validate(String input) throws ValidationException{
if (input.equals("")) throw new ValidationException("Input was empty");
}
}
Then, my processing class, which got the validator object before via dependency injection would call validator.validate(input)
A good point about this design is, that
However, my doubts are in the design of the Validator. According to OO, it misses some kind of state. With this design, it is as util class and the validate method could be static
. And I read a lot of times that (static) Util classes are bad OO design. So, how can this be done with more OO while keeping the two advantages I mentioned?
PS.: Maybe, OO is simply a bad solution for this kind of problem. However, I would like to see how the OO solution would look like and form my own opinion.
The validator in your example doesn't have a state (and doesn't need any), but another validator could require one (say with a format):
Example:
public class RegExValidator {
private Pattern pattern;
public RegExValidator(String re) {
pattern = Pattern.compile(re);
}
public void validate(String input) throws ValidationException {
if (!pattern.matcher(input).matches()) {
throw new ValidationException("Invalid syntax [" + input + "]");
}
}
}
Concentrating on the OOP aspect of your question (rather than the question if an Exception is the correct way to handle your validation):
Why have a single validator?
interface Validator<T> {
void validate(T toValidate) throws ValidationException;
}
would enable you to write classes that can validate any class T
and be very testable. Your validator would look like this:
class EmptyStringValidator implements Validator<String> {
public void validate(String toValidate) {
if(toValidate == null || toValidate.isEmpty()) throw new ValidationException("empty!!!");
}
}
and you could test it very easily. In fact, if you're using Java 8, this would be a functional interface, so a single utility class could host several validators:
class ValidationUtil {
public static void emptyString(String val) // same code as above
}
and ValidationUtil::emptyString
would implement Validator<String>
.
You would combine several validators with a composite pattern.
You could also have a validator with a state if that's what you need...
class ListIsSortedValidator implements Validator<Integer> {
private int lastInt = Integer.MIN_VALUE;
public void validate(Integer val) throw ValidationException {
if (val < lastInt) throw new ValidationException("not sorted");
lastInt = val;
}
}
That you could use to for instance validate a list:
List<Integer> list = createList();
Validator<Integer> validator = new ListIsSortedValidator();
list.forEach(validator::validate);
It depends on the circumstances of course, but I think your instinct is correct. This design could be more Object-Oriented.
It is not just that Validator
has no state, which is a purely mechanical indicator that it is likely not a correct abstraction, but the name itself tells us something. Usually Validator
(or even EmptyStringValidator
) is not part of the problem domain. It is always a bad sign when you have to create something purely technical (although sometimes it is the less of two evils).
I assume you are not writing a web-framework, you are trying to write an application that has some domain. For example it has user registration. Then, RegistrationForm
is part of the problem domain. Users know about the "registration form", you can talk about it and they will know what you mean.
In this case, an Object-Oriented solution for validation would be that this object is responsible for the validation of itself during the "submitting" of itself.
public final class RegistrationForm extends Form {
...
@Override
public void submit() {
// Do validation here
// Set input fields to error if there are problems
// If everything ok do logic
}
}
I know this is not the solution normally seen or even supported by web-frameworks. But it is how an Object-Oriented solution would look like.
The two important points to always keep in mind are:
Validator
(if that's not your application's domain).Firebase Cloud Functions: PubSub, "res.on is not a function"
TypeError: Cannot read properties of undefined (reading 'createMessageComponentCollector')
We have a simple JSF + PrimeFaces 61 project which is for now a POC to solve a problem that we have in our actual project, which is basically the need to load JSF/PF components concurrently
I want to find the maximum value in a map along with the keyIf there are multiple values then return all the entries
I want my Java program to log the dependencies before anythingI am aware of the mvn dependency:tree command, but the Jar file created will not be executed on a computer with Maven
I want to put the scanner object to take integer input from console into a separate class which can be imported and used in other filesI have been trying alot checking all the procedures to create a package correctly but still everything fails