Why is it considered such an anti-pattern in all cases to use static methods rather than singletons?
I originally wrote the following code
class MyValidator {
public static boolean isValid(String mystring){
if (some conditions ...) {
return true
} else {
return false
}
}
}
I can't really see a reason to make this into an object. It seems just fine as a static method - more testable, eliminating state, etc.
However, I ran into an issue upstream when I wanted to write a controller unit test and mock out the isValid() call. I realize I can use libraries like PowerMock, but people seem to religiously think doing this is an antipattern.
Why is that and what's so wrong with keeping this static?
an anti-pattern in all cases to use static methods rather than singletons
This is not true. In some cases static methods are absolutely fine, in others not.
Here are some examples from widely used libraries when it is perfectly fine to use static methods:
There are no strict criteria in what case static method can be used or should not be used. For some developers this is a matter of their personal preferences, to use static methods as much as possible, or vice versa, to avoid static methods as much as possible.
If you have no strong preferences, you may consider following criteria to decide.
To your case with MyValidator: I would suppose that later on you may need more than one validator and some generic logic that iterates over list of attributes, determines validators for each attribute and applies them. With static methods it will be very hard to implement it. Where as with non-static methods it may be much easier. For instance, it would be easier to define a generic structure of such classes as following:
public interface Validator<T> {
boolean isValid(T target);
}
Then applying such may be very compact:
for (...) {
validator = findValidatorForObject(obj);
// No need to check the type: String, Integer, ...
if (!validator.isValid(obj)) {
...
}
}
I believe you're setting up a false dichotomy in static methods vs. singletons. Singletons often create problems because they hold state that is hidden from the clients of the classes that access the singletons. But as an alternative to static methods they would not hold state.
Another alternative is for you to define an interface that can be filled with your static method in production code and a mock in testing code:
interface Validator {
boolean isValid(String string);
}
class ClassThatUsesValidator {
private final Validator validator;
public ClassThatUsesValidator(Validator validator) {
this.validator = validator;
}
public void methodToTest(String value) {
if (validator.isValid(value))
...
}
}
// production code
ClassThatUsesValidator obj = new ClassThatUsesValidator(MyValidator::isValid);
// test code
Validator mock = mock(Validator.class);
when(mock.isValid("foo")).thenReturn(false);
ClassThatUsesValidator testObj = new ClassThatUsesValidator(mock);
testObj.methodToTest("foo");
assertThat ...
This way you are avoiding a singleton, using a static method and are still able to mock it for testing.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.