Como el principio de segregación de interfaz sugiere que ningún cliente debería verse obligado a depender de métodos que no utiliza, por lo que un cliente no debe implementar un método vacío para sus métodos de interfaz, de lo contrario, este método de interfaz debe colocarse en otra interfaz.
¿Pero qué hay de los métodos concretos? ¿Debo separar los métodos que no todos los clientes usarían? Considere la siguiente clase:
public class Car{
....
public boolean isQualityPass(){
...
}
public int getTax(){
...
}
public int getCost(){
...
}
}
public class CarShop{
...
public int getCarPrice(int carId){
Car car=carList[carId];
int price=car.getTax() + car.getCost()... (some formula);
return price;
}
}
en el código anterior, CarShop no utiliza el método isQualityPass () en Car, si separo isQualityPass () en una nueva clase:
public class CheckCarQualityPass{
public boolean isQualityPass(Car car){
}
}
para reducir el acoplamiento de CarShop? Porque creo que una vez si isQualityPass () necesita dependencia adicional, por ejemplo:
public boolean isQualityPass(){
HttpClient client=...
}
CarShop dependería de HttpClient incluso si nunca usa HttpClient en realidad. Entonces mi pregunta es: de acuerdo con el principio de segregación de interfaz, ¿debería separar métodos concretos que no todos los clientes usarían, de modo que esos métodos dependan del cliente solo cuando el cliente realmente lo use, para reducir el acoplamiento?
fuente

Carclase que no desea que (todos) los usuarios conozcan, cree (más de una) interfaz que laCarclase implemente y que declare solo métodos útiles en el contexto de las interfaces.Respuestas:
En su ejemplo,
CarShopno dependeisQualityPassy no está obligado a realizar una implementación vacía para un método. Ni siquiera hay una interfaz involucrada. Entonces, el término "ISP" simplemente no coincide aquí. Y siempre que un método comoisQualityPasssea un método que se ajuste bien alCarobjeto, sin sobrecargarlo con responsabilidades o dependencias adicionales, está bien. No es necesario refactorizar un método público de una clase en otro lugar solo porque existe un cliente que no usa el método.Sin embargo, hacer que una clase de dominio
Cardependa directamente de algo asíHttpClientprobablemente tampoco sea una buena idea, independientemente de qué clientes usen o no el método. Mover la lógica a una clase separadaCheckCarQualityPasssimplemente no se llama "ISP", esto se llama "separación de preocupaciones" . La preocupación de un objeto de automóvil reutilizable probablemente no debería ser hacer ninguna llamada HTTP externa, al menos no directamente, esto limita la reutilización y, además, la comprobabilidad demasiado.Si
isQualityPassno se puede mover fácilmente a otra clase, la alternativa sería hacer lasHttpllamadas a través de una interfaz abstractaIHttpClientque se inyecta en elCarmomento de la construcción, o inyectando toda la estrategia de verificación "QualityPass" (con la solicitud Http encapsulada) en elCarobjeto . Pero esa es, en mi humilde opinión, la segunda mejor solución, ya que aumenta la complejidad general en lugar de reducirla.fuente
Carobjeto más complejo . No sería mi primera opción para una solución (al menos no en el contexto de este ejemplo artificial). Sin embargo, puede tener más sentido en el código "real", no lo sé.El principio de segregación de interfaz no se trata de impedir el acceso a lo que no necesita. Se trata de no insistir en el acceso a lo que no necesita.
Las interfaces no son propiedad de la clase que las implementa. Son propiedad de los objetos que los usan.
Lo que se usa aquí es
getTax()ygetCost(). En lo que se insiste es en todo lo accesibleCar. El problema es insistir enCarsignifica que insiste en el acceso alisQualityPass()cual no es necesario.Esto se puede arreglar. Usted pregunta si se puede arreglar concretamente. Puede.
Ninguno de ese código sabe si
CarLiabilityes una interfaz o una clase concreta. Eso es bueno. No quiere saberlo.Si es una interfaz,
Carpodría implementarlo. Esto no violaría a ISP porque aunqueisQuality()está adentroCarCarShopno insiste en ello. Esto esta bien.Si es concreto, es posible que
isQuality()no exista o se haya mudado a otro lugar. Esto esta bien.También podría ser que se
CarLiabilitytrata de una envoltura de concretoCarque le delega trabajo. MientrasCarLiabilityno se exponga,isQuality()entoncesCarShopestá bien. Por supuesto, esto simplemente patea la lata en el camino yCarLiabilitytiene que descubrir cómo seguir al ISP deCarla misma manera queCarShoptenía que hacerlo.En resumen,
isQuality()no es necesario eliminarloCardebido a ISP. La necesidad implícita deisQuality()necesidades debe eliminarseCarShopporqueCarShopno la necesita, por lo que no debe solicitarla.fuente
Realmente no. Hay diferentes maneras de ocultar
Car.isQualityPassaCarShop.1. Modificadores de acceso
Desde el punto de vista de la Ley de Deméter , podríamos considerar
CaryCardShopno ser amigos . Nos legitima para hacer lo siguiente.Tenga en cuenta que ambos componentes están en paquetes diferentes. Ahora
CarShopno tiene visibilidad sobre comportamientosCarprotegidos . (Disculpe de antemano si el ejemplo anterior parece tan simplista).2. Segregación de interfaz
El ISP funciona desde la premisa de que trabajamos con abstracciones, no con clases concretas. Asumiré que ya está familiarizado con la implementación del ISP y con las interfaces de roles .
A pesar de la
Carimplementación real , nada nos impide practicar ISP.Lo que he hecho aquí. He reducido la interacción entre
CaryaCarShoptravés de la interfaz de rol Facturable . Tenga en cuenta el cambio en lagetPricefirma. He modificado intencionalmente el argumento. Quería hacer obvio queCarShopsolo está "vinculado / vinculado" a una de las interfaces de roles disponibles. Podría haber seguido la implementación real pero no conozco los detalles de la implementación real y me temo que elgetPrice(String carId)acceso real (visibilidad) sobre la clase concreta. Si es así, todo el trabajo realizado con el ISP se vuelve inútil porque está en manos del desarrollador hacer el casting y trabajar solo con la interfaz Facturable . No importa lo metódicos que seamos, la tentación siempre estará ahí.3. Responsabilidad individual
Me temo que no estoy en condiciones de decir si la dependencia entre
CaryHttpClientes adecuada, pero estoy de acuerdo con @DocBrown, plantea algunas advertencias que merecen una revisión de diseño. Ni la Ley de Demeter ni el ISP harán que su diseño sea "mejor" en este momento. Simplemente enmascararán el problema, no lo solucionarán.He sugerido DocBrown el Patrón de estrategia como una posible solución. Estuve de acuerdo con él en que el patrón agrega complejidad, pero también creo que cualquier rediseño lo hará. Es una compensación, cuanto más desacoplamiento queremos, más partes móviles tenemos (generalmente). De todos modos, creo que ambos están de acuerdo con que un nuevo diseño es muy recomendable.
Resumiendo
No, no necesita mover métodos concretos a clases externas para no hacerlos accesibles. Podría haber innumerables consumidores. ¿Moverías todos los métodos concretos a clases externas cada vez que un nuevo consumidor entra en juego? Espero que no
fuente