Home > Blockchain >  How to avoid empty visit functions in visitor pattern?
How to avoid empty visit functions in visitor pattern?

Time:10-03

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.

CodePudding user response:

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.

CodePudding user response:

I have just one note that 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?

  • Related