Interface Segregation Principle with "optional" methods in Implementation

jdoe :

Interface Segregation Principle from SOLID says that Classes shouldn't have to implement/depend on methods they do not need. You should never have //Not used: just needed to implement interface in the codebase.

How do I apply this principle when some methods are "optional" by their nature because the implementation class is a specific corner case.

Say I have this interface example:

Interface Input {
    Input create();
    void capitalizeInput(CAPITALIZATION cap);
    String getInput();
}

Class LatinInput implements Input {
    String input;
    Input create(String input){...}
    void capitalizeInput(CAPITALIZATION cap){...}
    String getInput(){...}
}

Class NumberOnlyInput implements Input {
    int input;
    Input create(int input){...}
    void capitalizeInput(CAPITALIZATION cap){
         // Needed because the interface requires it.
         return;
    }
    String getInput(){...}
}

That interface is used widely in the program by other classes. Currently in my programs I am doing something like the following.

Class B {
    Input input;
    B(Input input){
       this.input = input;
    }

    String doStuff(){
        ...
        methodA();
        ...
        methodB();
        ...
        methodC();
        ...
        methodA();
        ...
        return ...;
    }

    private void methodA(){
        ...
        input.transformInput(CAPITAL);
        input.getInput();
    }

    private void methodB(){
        ...
        input.getInput();
    }

    private void methodC(){
        ...
        input.transformInput();
    }
}

And it is called by a clas C;

Class C {
    void doStuff() {
        List<A> list = new Arraylist<>();
        list.add(LatinInput.create("hello"));
        list.add(LatinInput.create("goodbye"));
        list.add(NumberOnlyInput.create(12345));

        for(Input input: list){
            B b = new B(a);
            b.doStuff();
        }
    }
}

How should I change the design to comply with ISP, without changing class C, while also not needing to check if the object is instance of during runtime?

Piotr Praszmo :

Interface segregation principle:

states that no client should be forced to depend on methods it does not use.

It doesn't say anything about implementing methods with empty body. Your class B uses both capitalizeInput and getInput, as long as those are only two methods in Input, it doesn't violate interface segregation principle. In your case B uses NumberOnlyInput.capitalizeInput it just so happens that empy body is a valid implementation of this functionality.

However, Input.create does violate ISP. B depends on Input but doesn't use Input.create - it is not called at all. In that case, you can just remove it from the interface.

You can still get rid of that strange empty method. Since NumberOnlyInput is special case of LatinInput you can reuse that class:

class NumberOnlyInput {
    static Input create(int input) {
        return new LatinInput(String.valueOf(input));
    }
}

It might be less clear or performant - which might be why special case for numbers was created in the first place.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=358584&siteId=1