Reputation: 27455
I have two separate entities:
public enum Rule implements Validatable, StringRepresentable{
//...
}
and
public inteface Filter extends Validatable, StringRepresentable{
//...
}
Where
public inteface Validatable{
public GenericValidator getValidator();
}
and
public interface StringRepresentable{
public String getStringRepresentation();
}
GenericValidator
is an abstract class having a number of subclasses I would not like users to access directly. How should I handle those things better?
I don't understand when it's better to create a class like
public class ValidatorFactory{
public Validator getRuleValidator(Rule r){ ... }
public Validator getFilterValidator(Filter f){ ... }
}
instead of implementing the Validatable
interface as I shown earlier.
Couldn't someone explain how can I make a right decision? What potentiall circumstances requires implementing FactoryMethod
a bad decision and when it would be really good?
UPD:
public interface Validator{
public ErrorCode validate();
}
public abstract class GenericValidator implements Validator{
//...
}
The ErrorCode
class encapsulates the result of the validation (null
if valiadtion's completed succsfully).
Upvotes: 5
Views: 130
Reputation: 4301
Validator interface can look like this:
public interface Validator {
public int validate();
}
Filter interface can look like this:
public interface Filter {
public String getParameters(); // some related methods..
public int currentLength();
....
}
Rule interface:
public interface Rule {
public String getRule();
}
FilterValidator can look like this:
public class FilterValidator implements Validator{
private Filter f;
public FilterValidator(Filter f){
this.f = f;
}
@Override
public int validate() {
// validate f and return errorcode
String params = f.getParameters();
int strLength = f.currentLength();
.....
return 0;
}
}
Creating a factory is better to hide the internal logic of validators.
public class ValidatorFactory {
public Validator getRuleValidator(Rule r){
return null;
}
public Validator getFilterValidator(Filter f){
FilterValidator fv = new FilterValidator(f);
return fv;
}
}
Now client will invoke this factoy like this:
public class ClientDemo {
private class MyFilter implements Filter{
private String filterInput;
public MyFilter(String input){
this.filterInput = input;
}
@Override
public String getParameters() {
return null;
}
@Override
public int currentLength() {
return this.filterInput.length();
}
}
public void testValidators(){
ValidatorFactory factory = new ValidatorFactory();
Validator v = factory.getFilterValidator(new MyFilter("filter string goes here..."));
v.validate();
}
}
}
Through the interfaces Rule, Filter you can enforce the behavior you desire from client. Then client can get instances from the factory and pass the rule/filter instances to it for validation.
Upvotes: 3
Reputation: 5220
The Single Responsibility Principle
Construction of Validator is one responsibility, Filter or Rule probably carries another one. This means we should split it and usually we do so encapsulating instantiation logic in a Factory pattern.
Also note that implementing Validatable means being a ValidatorFactory. My answer would be - combine both solutions:
public class FilterImpl implements Filter {
private final Validator validator;
public FilterImpl(Validator validator) {
this.validator = validator;
}
@Override
public getValidator() {
return this.validator;
}
//...
}
public class FilterFactory {
private final ValidatorFactory validatorFactory = new ValidatorFactory();
public Filter createFilter() {
return new FilterImpl(valdatorFactory.createFilterValidator());
}
}
This is called Dependency Injection.
Upvotes: 3
Reputation: 3031
I use this pattern in two major cases:
A) Construction of the object isn't trivial - I don't trust the users of the API to do it correctly
B) There are more implementations and I want to choose the right one myself.
In both these cases I want to hide implementations simply because the user won't know which one to use and/or doesn't know how to construct it properly.
Always aim for simplicity and ease-of-use for your user. Ask yourself these questions:
Upvotes: 3