Является ли принцип сепарации интерфейса только заменой принципа единой ответственности?
Является ли принцип сепарации интерфейса только заменой принципа единой ответственности?
Я думаю, что если мой класс выполняет SRP, нет необходимости извлекать более одного интерфейса.
Таким образом, ISP выглядит как решение в случае, если нам по какой-то причине нужно сломать SRP.
Я прав?
Ответы
Ответ 1
Нет. Возьмем пример класса, ответственность которого сохраняется за данные, например. жесткий диск. Разделение класса на часть чтения и записи не имеет практического смысла. Но некоторые клиенты должны использовать только класс для чтения данных, некоторые клиенты - только для записи данных, а некоторые - для обоих. Применение ISP здесь с тремя различными интерфейсами было бы хорошим решением.
Ответ 2
Я думаю, что если мой класс выполнит SRP, нет необходимости извлекать больше чем один интерфейс.
Принцип единой ответственности заключается в том, что класс (или метод) не должен иметь более чем одну причину изменения (т.е. каждый несет ответственность только за одну функцию). В честь этого вы обнаружите, что создаете новые классы по мере развития вашей системы.
например. если вы начинаете с класса Car
и обнаружите, что вам нужна функциональность для переключения передач, вы извлечете его в класс Gearbox
. Это означает, что если вы измените механизм переключения передач, родительский класс Car
не нуждается в изменении. Если вы добавите рулевое управление с усилителем в свой автомобиль, вы снова извлечете его в свой класс. Радио будет другим классом.
Этот каскад абстракции будет происходить в вашем классе Car
. Когда вы переходите от самого Car
вниз, вы обнаружите, что деталь увеличивается в каждом классе - например. в то время как класс Car
может иметь метод changeGear()
, позволяющий пользователю выбирать механизм для включения, класс Gearbox
будет следить за тем, как это происходит (например, нажмите на муфту, отключите текущую передачу, выберите новую передачу и т.д.)
Однако с дизайном OO мы не хотим раскрывать детали нашего Gearbox
конечному пользователю - мы хотим, чтобы они взаимодействовали с нашей системой на высоком уровне абстракции, не зная, как внутренние элементы Работа. Мы также хотим закрепить эти внутренние элементы, чтобы мы могли изменить их в будущем, не требуя, чтобы пользователи реорганизовали свой код (поэтому мы будем отмечать их как private
или protected
).
Из-за этого мы позволяем пользователям взаимодействовать с нашим автомобилем только через класс Car
. В этом случае используется принцип разделения сегментов. SRP гарантирует, что класс Car
делегирует свои подкомпоненты различным классам, но все наши методы public
будут по-прежнему вызываться через Car
сам класс. ISP гарантирует, что вместо объединения всех этих компонентов в один интерфейс мы вместо этого создадим логические различия и выставим несколько интерфейсов для связанных функций.
Ответ 3
Нет.
Класс может реализовывать несколько интерфейсов, но он должен применять методы, применимые только к нему.
Предположим, что у вас есть 10 + различных возможностей, таких как Climb, Think, Learn, Apply
. Класс Dog
может иметь 2 возможности, а класс Cat
может иметь 2 возможности, а класс Man
может иметь 6 возможностей. Имеет смысл реализовать только применимые возможности в соответствующих классах.
Посмотрите на этот код.
public class ISRDemo{
public static void main(String args[]){
Dog dog = new Dog("Jack",16);
System.out.println(dog);
Learn dl = dog;
dl.learn();
ProtectOwner p = dog;
p.protectOwner();
Cat cat = new Cat("Joe",20);
System.out.println(cat);
Climb c = cat;
c.climb();
Remember r = cat;
cat.doRemember();
Man man = new Man("Ravindra",40);
System.out.println(man);
Think t = man;
t.think();
Learn l = man;
l.learn();
Apply a = man;
a.apply();
PlaySports pm = man;
pm.playSports();
Remember rm = man;
rm.doRemember();
}
}
class Dog implements Learn,ProtectOwner{
private String name;
private int age;
public Dog(String name,int age){
this.name = name;
this.age = age;
}
public void learn(){
System.out.println(this.getClass().getSimpleName()+ " can learn");
}
public void protectOwner(){
System.out.println(this.getClass().getSimpleName()+ " can protect owner");
}
public String toString(){
return "Dog :"+name+":Age:"+age;
}
}
class Cat implements Climb,Remember {
private String name;
private int age;
public Cat(String name,int age){
this.name = name;
this.age = age;
}
public void climb(){
System.out.println(this.getClass().getSimpleName()+ " can climb");
}
public void doRemember(){
System.out.println(this.getClass().getSimpleName()+ " can remember");
}
public String toString(){
return "Cat :"+name+":Age:"+age;
}
}
interface ProtectOwner {
public void protectOwner();
}
interface Remember{
public void doRemember();
}
interface Climb{
public void climb();
}
interface Think {
public void think();
}
interface Learn {
public void learn();
}
interface Apply{
public void apply();
}
interface PlaySports{
public void playSports();
}
class Man implements Think,Learn,Apply,PlaySports,Remember{
String name;
int age;
public Man(String name,int age){
this.name = name;
this.age = age;
}
public void think(){
System.out.println(this.getClass().getSimpleName() + " can think");
}
public void learn(){
System.out.println(this.getClass().getSimpleName() + " can learn");
}
public void apply(){
System.out.println(this.getClass().getSimpleName() + " can apply");
}
public void playSports(){
System.out.println(this.getClass().getSimpleName() + " can play sports");
}
public void doRemember(){
System.out.println(this.getClass().getSimpleName() + " can remember");
}
public String toString(){
return "Man :"+name+":Age:"+age;
}
}
выход:
java ISRDemo
Dog :Jack:Age:16
Dog can learn
Dog can protect owner
Cat :Joe:Age:20
Cat can climb
Cat can remember
Man :Ravindra:Age:40
Man can think
Man can learn
Man can apply
Man can play sports
Man can remember
В приведенном выше примере сегрегация интерфейса рекомендует определить 10 возможностей в 10 интерфейсах вместо объявления всех из них в жирном интерфейсе. Но это не значит, что вам нужны разные классы, чтобы соответствовать единым критериям ответственности.
Посмотрите на реализацию классов Dog, Cat and Man
в том же примере.