I have the following use case. I have a restriction interface that needs to fill its members from dependencies, do the validations. These methods are applicable for all implementations and hence it is fine till now. Some restrictions require some other validation later. In the main function, I want to loop over each of the restriction and call the methods in a general way instead of using instanceOf and then calling. I think this might be a use case of visitor pattern as mentioned here . Now I have the following classes.
interface Restriction() {
void fillFields();
void firstRoundValidation();
void accept(SecondRoundValidationVisitor secondRoundValidationVisitor);
}
class RestrictionBasic implements Restriction {
Field field;
// Inject dependencies
@Override
void fillFields() {
// Get field from dependencies
}
void firstRoundValidation() {
// Implement
}
@void accept(SecondRoundValidationVisitor secondRoundValidationVisitor) {
secondRoundValidationVisitor.visitRestrictionBasic(this);
}
}
class RestrictionAdvanced implements Restriction {
// Same as above except below function.
@void accept(SecondRoundValidationVisitor secondRoundValidationVisitor) {
secondRoundValidationVisitor.visitRestrictionAdvanced(this);
}
}
interface ValidationVisitor {
void visitRestriction(RestrictionBasic restrictionBasic);
void visitRestriction(RestrictionAdvanced restrictionAdvanced);
}
class SecondRoundValidationVisitor implements ValidationVisitor {
@Override
void visitRestriction(RestrictionBasic restrictionBasic) {
// Empty function
}
@Override
void visitRestriction(RestrictionAdvanced restrictionAdvanced) {
// Perform second level of validation
}
}
class Main() {
List<Restriction> restrictionList = new ArrayList();
ValidationVisitor validationVisitor = new SecondRoundValidationVisitor();
for (restriction : restrictionList) {
restriction.accept(validationVisitor)
}
}
Could you please tell if there is any issue with this approach? There is also another approach where getSecondValidationNeeded() could be added to the interface and based on that, call secondValidation with default value of empty body. But this is not following interface segregation principle. My doubt is how does visitor pattern solve this issue? Even in visitor pattern, there is only one interface and accept is being added in base interface even when only some visitors have non empty visit functions.
Pattern-wise I don't think there is a problem. visitRestrictionBasic is only empty because apparently you don't have second round validation for basic restrictions. This is a business rule, not a flaw of the design. If you later decide that you DO want second round validation for basic restrictions, you know where you can add it.
Apart from that, the whole set up might be overkill. It's usually good to start off simple. But I don't know your complete domain and use case, so cannot judge if this is the case here.
EDIT: To evaluate your approach we should get more context and take a step back to understand the problem. So far what I understand is there are several restriction types which have the following characteristics:
The fundamental difference between the first round and second round validation is not clear to me. Both of them have specific validation code for each restriction type if I understand it correctly. If not, and the basic validator is only used in the first round, and the advanced validator only in the second round, then the model could probably be simplified. In that case first round = basic and second round = advanced...
Visitor pattern uses overloading of methods to choose appropriate implementation. It can be seen in a wiki example :
interface CarElementVisitor {
void visit(Body body);
void visit(Car car);
void visit(Engine engine);
void visit(Wheel wheel);
}
So I would edit interface ValidationVisitor
:
interface ValidationVisitor {
void visitRestrictionBasic(RestrictionBasic restrictionBasic);
void visitRestrictionAdvanced(RestrictionAdvanced restrictionAdvanced);
}
to this:
public interface ValidationVisitor
{
void VisitRestriction(RestrictionBasic restrictionBasic);
void VisitRestriction(RestrictionAdvanced restrictionAdvanced);
}
So we have created VisitRestriction()
with different overloads.
Why? If you don't know the type of the object? You probably would need to find out the real type of Restriction
and then call VisitRestrictionBasic
or VisitRestrictionAdvanced
. I highly recommend you to read this very nice answer about What's the point of the accept
method ?
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.