ktschanz
ktschanz

Reputation: 21

Interface segregation principle application

I'm wondering if the Interface segregation principle applys to my codebase.

Here's some example code:

First Class:

public class EntityGroup {
    public List<Entity> tests;

    //returns true if the EntityGroup is valid
    public boolean validate() {
        for (Entity test : tests) {
            if (!test.validateFieldA() || !test.validateFieldB()) {
                return false;
            }
        }
        return true;
    }

}

Second Class:

public abstract class Entity {

    protected String fieldA;

    public abstract boolean validateFieldA();

    public abstract boolean validateFieldB();

}

Third Class:

public class EntityChild extends Entity {
    private String fieldB;


    @Override
    public boolean validateFieldA() {
        if (fieldA.equals("valid")) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean validateFieldB() {
        if (fieldB.equals("valid")) {
            return true;
        } else {
            return false;
        }
    }
}

Fourth Class:

 public class EntityChild2 extends Entity {

    @Override
    public boolean validateFieldA() {
        if (fieldA.equals("valid")) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean validateFieldB() {
        return true;
    }
}

This is a greatly simplified example from my real codebase but I think it illustrates the problem well. My EntityChild2 class is forced to implement a method it does not need or want to know about.

I know that it would be more correct to have a Interface that would contain the validateFieldB() method and only have EntityChild implement that interface.

With the understanding that this would take a significant amount of effort to refactor into this solution, I'm having a hard time justifying the time it would take to implement this solution in my real code base.

What potential problems will I run into down the line by leaving my code this way?

What benefits will I gain from refactoring my code to have a separate interface for validateFieldB()?

tldr: Why is the Interface Segregation Principle so important?

Upvotes: 1

Views: 146

Answers (1)

Roman
Roman

Reputation: 5210

Wrong Abstraction

You make use of the interface segregation principle but with wrong abstractions.. Your different Entity-types differ only in they behavior.

Because of the shared behavior you have duplicate code in the methods validateFieldA of EntityChild and EntityChild2 . The method validateFieldB looks very similar to validateFieldA just the filed for checking the equality is an other.

You only need one Entity

Strategy Pattern

With the Strategy-Pattern you will have no duplicate code:

class EqualValidationStategy() implements ValidationStategy<T> {
    @Override
    public boolean check(T a, T b) {
        return a.equals(b)
    }
}

class TrueValidationStategy() implements ValidationStategy<T> {
    @Override
    public boolean check(T a, T b) {
        return true;
    }
}

Entity

public class Entity {
    private String fieldA;
    private String fieldB;
    private ValidationStategy<String> validationForA;
    private ValidationStategy<String> validationForB;

    // all-args consturctor

    @Override
    public boolean validateFieldA() {
        return validationForA.check(fieldA, "valid");
    }

    @Override
    public boolean validateFieldB() {
        return validationForB.check(fieldB, "valid");
    }
}



// Validates fieldA and "ignores" fieldB
Entity example = new Entity(fieldA, 
                            fieldB, 
                            new EqualValidationStategy(), 
                            new TrueValidationStategy());

Upvotes: 1

Related Questions