Принцип разделения интерфейса с "необязательными" методами в реализации
Принцип разделения интерфейса от SOLID гласит, что классы не должны реализовывать / зависеть от методов, которые им не нужны. У тебя никогда не должно быть//Not used: just needed to implement interface
в базе кода.
Как применить этот принцип, если некоторые методы являются "необязательными" по своей природе, потому что класс реализации - это особый угловой случай.
Скажем, у меня есть этот пример интерфейса:
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 ответ
Принцип разделения интерфейса:
заявляет, что ни один клиент не должен зависеть от методов, которые он не использует.
Здесь ничего не говорится о реализации методов с пустым телом. Твой класс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));
}
}
Он может быть менее ясным или эффективным - возможно, поэтому в первую очередь был создан специальный регистр для чисел.