Estoy en una situación muy similar a la que ha mencionado Steve McConnell's en Code Complete. Solo que mi problema está basado en Vehículos y Trike pasa a estar en eso por ley cae en la categoría de Autos. Los autos tenían cuatro ruedas hasta ahora. De todos modos, mi dominio es innecesariamente complejo, por lo que es fácil seguir el siguiente ejemplo de gatos.¿Cómo puedo evitar romper el Principio de sustitución de Liskov (LSP)?
sospechar de clases que anulan una rutina y no hacen nada dentro de la rutina derivada Normalmente, esto indica un error en el diseño de la clase base. Por ejemplo, supongamos que tiene una clase Cat y una rutina Scratch() y suponga que finalmente descubre que algunos gatos están destripados y no pueden rayar. Es posible que tenga la tentación de crear una clase derivada de Cat llamada ScratchlessCat y anular la rutina Scratch() para no hacer nada. Este enfoque presenta varios problemas:
Viola la abstracción (contrato de interfaz) presentada en la clase Cat al cambiar la semántica de su interfaz.
Este enfoque se sale de control rápidamente cuando lo extiende a otras clases derivadas . ¿Qué pasa cuando encuentras un gato sin cola? O un gato que no atrapa ratones? ¿O un gato que no bebe leche? Eventualmente terminarás con clases derivadas como ScratchlessTaillessMicelessMilklessCat.
Con el tiempo, este enfoque da lugar a código que confunde a mantener porque las interfaces y el comportamiento de las clases antecesoras implican poco o nada sobre el comportamiento de sus descendientes.
El lugar para solucionar este problema no está en la clase base, sino en la clase Cat original . Cree una clase Claws y contenga eso dentro de la clase Cats . El problema de raíz fue la suposición de que todos los gatos se rascan, , por lo tanto, solucione ese problema en la fuente, en lugar de simplemente vendarlo en el destino .
De acuerdo con el texto de su gran libro anterior. Lo que sigue es mala
clase principal no tiene que ser abstracta
public abstract class Cat {
public void scratch() {
System.out.println("I can scratch");
}
}
clase derivada
public class ScratchlessCat extends Cat {
@Override
public void scratch() {
// do nothing
}
}
Ahora se sugiere la creación de otra clase Claws
, pero yo no entiendo cómo puede Uso esta clase para evitar la necesidad de ScratchlessCat#Scratch
.
El ejemplo del gato es una buena ilustración de la LSP. Al conocer LSP, me sorprendió ver cuántos ejemplos pobres y cuántos malentendidos hay en SO y otros sitios. – SteveT