Принцип разделения интерфейса с «дополнительными» методами в реализации - PullRequest
1 голос
/ 11 января 2020

Принцип разделения интерфейса от SOLID говорит, что классы не должны реализовывать / зависеть от методов, которые им не нужны. Вы никогда не должны иметь //Not used: just needed to implement interface в кодовой базе.

Как применять этот принцип, когда некоторые методы являются «необязательными» по своей природе, потому что класс реализации является конкретным c угловым случаем.

Скажем, у меня есть такой пример интерфейса:

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(){...}
}

Этот интерфейс широко используется в программе другими классами. В настоящее время в своих программах я делаю что-то вроде следующего:

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();
    }
}

И это вызывается классом 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();
        }
    }
}

Как мне изменить дизайн, чтобы соответствовать ISP, без изменения класса C, при этом также не нужно проверять, является ли объект instance of во время выполнения?

1 Ответ

2 голосов
/ 11 января 2020

Принцип сегрегации интерфейса :

гласит, что ни одного клиента не следует заставлять зависеть от методов, которые он не использует.

Это не ' ничего не сказать о реализации методов с пустым телом. Ваш класс B использует как capitalizeInput, так и getInput, поскольку в Input это всего лишь два метода, он не нарушает принцип разделения интерфейса. В вашем случае B использует NumberOnlyInput.capitalizeInput, так что случается так, что empy body является допустимой реализацией этой функциональности.

Однако, Input.create нарушает ISP. B зависит от Input, но не использует Input.create - он вообще не вызывается. В этом случае вы можете просто удалить его из интерфейса.

Вы все еще можете избавиться от этого странного пустого метода. Поскольку NumberOnlyInput является особым случаем LatinInput, вы можете повторно использовать этот класс:

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

Он может быть менее понятным или производительным - возможно, именно поэтому вначале был создан особый случай для чисел.

...