La guía paso a paso o código que verás en este post es la resolución más rápida y válida que hallamos a tus dudas o problema.
Solución:
Un gran ejemplo que ilustra LSP (dado por el tío Bob en un podcast que escuché recientemente) fue cómo a veces algo que suena bien en lenguaje natural no funciona del todo en código.
En matemáticas, un Square
es un Rectangle
. De hecho, es una especialización de un rectángulo. El “es un” hace que desee modelar esto con herencia. Sin embargo, si en el código hiciste Square
derivar de Rectangle
, Entonces un Square
debe ser utilizable en cualquier lugar donde espere un Rectangle
. Esto da lugar a un comportamiento extraño.
Imagina que tuviste SetWidth
y SetHeight
métodos en tu Rectangle
clase base; esto parece perfectamente lógico. Sin embargo, si tu Rectangle
referencia apuntaba a un Square
, entonces SetWidth
y SetHeight
no tiene sentido porque configurar uno cambiaría el otro para que coincida. En este caso Square
falla la prueba de sustitución de Liskov con Rectangle
y la abstracción de tener Square
heredar de Rectangle
es uno malo.
Todos deberían ver los otros carteles de motivación de los principios SOLID de valor incalculable.
El principio de sustitución de Liskov (LSP, lsp) es un concepto en programación orientada a objetos que establece:
Las funciones que usan punteros o referencias a clases base deben poder usar objetos de clases derivadas sin saberlo.
En esencia, LSP se trata de interfaces y contratos, así como de cómo decidir cuándo extender una clase o usar otra estrategia, como la composición, para lograr su objetivo.
La forma más eficaz que he visto de ilustrar este punto fue en Head First OOA & D. Presentan un escenario en el que eres un desarrollador de un proyecto para crear un marco para juegos de estrategia.
Presentan una clase que representa un tablero que se ve así:
Todos los métodos toman las coordenadas X e Y como parámetros para ubicar la posición del mosaico en el formato bidimensional. array de Tiles
. Esto permitirá al desarrollador del juego administrar unidades en el tablero durante el transcurso del juego.
El libro continúa cambiando los requisitos para decir que el marco del juego también debe admitir tableros de juegos en 3D para adaptarse a los juegos que tienen vuelo. Entonces un ThreeDBoard
se introduce una clase que se extiende Board
.
A primera vista, parece una buena decisión. Board
proporciona tanto el Height
y Width
propiedades y ThreeDBoard
proporciona el eje Z.
Donde se rompe es cuando miras a todos los otros miembros heredados de Board
. Los métodos para AddUnit
, GetTile
, GetUnits
y así sucesivamente, todos toman los parámetros X e Y en el Board
clase pero el ThreeDBoard
también necesita un parámetro Z.
Entonces debes implementar esos métodos nuevamente con un parámetro Z. El parámetro Z no tiene contexto para el Board
clase y los métodos heredados de la Board
la clase pierde su significado. Una unidad de código que intenta utilizar el ThreeDBoard
class como su clase base Board
estaría muy fuera de suerte.
Quizás deberíamos encontrar otro enfoque. En lugar de extender Board
, ThreeDBoard
debe estar compuesto de Board
objetos. Una Board
objeto por unidad del eje Z.
Esto nos permite utilizar buenos principios orientados a objetos como encapsulación y reutilización y no viola LSP.
La sustituibilidad es un principio en la programación orientada a objetos que establece que, en un programa de computadora, si S es un subtipo de T, entonces los objetos de tipo T pueden ser reemplazados por objetos de tipo S
Hagamos un ejemplo simple en Java:
Mal ejemplo
public class Bird
public void fly()
public class Duck extends Bird
El pato puede volar porque es un pájaro, pero ¿qué pasa con esto?
public class Ostrich extends Bird
El avestruz es un pájaro, pero no puede volar, la clase Avestruz es un subtipo de la clase Pájaro, pero no debería poder usar el método de la mosca, eso significa que estamos rompiendo el principio LSP.
Buen ejemplo
public class Bird
public class FlyingBirds extends Bird
public void fly()
public class Duck extends FlyingBirds
public class Ostrich extends Bird