design-patterns - solid - principios de diseño principio de inversion de dependencia
¿El principio de segregación de la interfaz es solo un sustituto del principio de responsabilidad única? (3)
¿El principio de segregación de interfaz es solo un sustituto del principio de responsabilidad única?
Creo que si mi clase cumple con SRP, no hay necesidad de extraer más de una interfaz.
Entonces ISP parece una solución en caso de que tengamos que romper SRP por alguna razón.
¿Estoy en lo cierto?
Creo que si mi clase cumple con SRP, no hay necesidad de extraer más de una interfaz.
El principio de responsabilidad única es que una clase (o un método) no debe tener más de un motivo para cambiar (es decir, cada responsable de una sola característica). Para honrar esto, te encontrarás creando nuevas clases a medida que tu sistema se desarrolle.
Por ejemplo, si comienzas con una clase de Car
y descubres que necesitas funcionalidad para cambiar los engranajes, extraerás esto en una clase de Gearbox
. Esto significa que si cambia el mecanismo detrás de los cambios de marcha, la clase de Car
principal no necesita cambiar. Si agrega la dirección asistida a su automóvil, nuevamente extraerá esto en su propia clase. La radio sería otra clase.
Esta cascada de abstracción sucederá a lo largo de tu clase de Car
. A medida que se desplaza del Car
hacia abajo, encontrará que el detalle aumenta en cada clase, por ejemplo, mientras que la clase Car
puede tener un método changeGear()
para permitir al usuario seleccionar una marcha para participar, la clase Gearbox
ocupará de la esencia de hacer que esto suceda (por ejemplo, presione el embrague, desconecte la marcha actual, seleccione la nueva marcha, etc.)
Sin embargo, con un diseño OO, no queremos exponer los detalles de nuestra Gearbox
al usuario final; queremos que interactúen con nuestro sistema a un alto nivel de abstracción, sin necesidad de saber cómo funcionan las piezas internas. También queremos delimitar estas partes internas, de modo que podamos cambiarlas en el futuro sin necesidad de que los usuarios refaccionalicen su código (razón por la cual los marcaríamos como private
o protected
).
Debido a esto, permitimos que los usuarios interactúen con nuestro automóvil solo a través de la clase Car
. Aquí es donde entra en juego el Principio de segregación de interfaz . SRP asegura que la clase Car
delegue sus subcomponentes en diferentes clases, pero todos nuestros métodos public
seguirán siendo llamados a través de la clase Car
. ISP garantiza que, en lugar de agrupar todos estos elementos en una sola interfaz, creamos distinciones lógicas y exponemos múltiples interfaces para funciones relacionadas.
No.
Una clase puede implementar múltiples interfaces pero debe implementar los métodos solo aplicables a ella.
Supongamos que tiene más de 10 capacidades diferentes, como Climb, Think, Learn, Apply
. Class Dog
puede tener 2 capacidades y la clase Cat
puede tener 2 capacidades y la clase Man
puede tener 6 capacidades. Tiene sentido implementar solo las capacidades aplicables en las clases respectivas.
Eche un vistazo a este código.
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;
}
}
salida:
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
En el ejemplo anterior, la segregación de la interfaz recomienda definir 10 capacidades en 10 interfaces en lugar de declarar todas ellas en la interfaz "gordo". Pero eso no significa que necesite diferentes clases para cumplir con los criterios de responsabilidad individuales .
Eche un vistazo a la implementación de las clases de Dog, Cat and Man
en el mismo ejemplo.
No. Tome el ejemplo de una clase cuya responsabilidad son los datos persistentes, por ejemplo, en el disco duro. Dividir la clase en una parte de lectura y escritura no tendría sentido práctico. Pero algunos clientes solo deben usar la clase para leer datos, algunos clientes solo para escribir datos y otros para hacer ambas cosas. La aplicación de ISP aquí con tres interfaces diferentes sería una buena solución.