Για τι ευθύνεται το γράμμα 'L' στις αρχές SOLID;
sobes.tech AI
Απάντηση από AI
Principio de sustitución de Liskov (Liskov Substitution Principle).
Según este principio, los objetos en un programa deben ser reemplazables por instancias de sus subtipos sin alterar la corrección del programa.
En otras palabras, si la clase B es un subtipo de la clase A, entonces cualquier objeto de tipo A en el programa puede ser reemplazado por un objeto de tipo B, y el programa seguirá funcionando correctamente.
Este principio ayuda a crear una arquitectura más flexible y resistente a cambios, minimizando efectos secundarios al trabajar con herencia.
Violación de LSP:
class Rectangle {
var width: Double
var height: Double
init(width: Double, height: Double) {
self.width = width
self.height = height
}
var area: Double {
return width * height
}
}
class Square: Rectangle { // El cuadrado es un subtipo del rectángulo
override var width: Double {
didSet {
height = width // Cambiar el ancho también cambia la altura
}
}
override var height: Double {
didSet {
width = height // Cambiar la altura también cambia el ancho
}
}
init(side: Double) {
super.init(width: side, height: side)
}
}
func calculateArea(of rectangle: Rectangle) -> Double {
return rectangle.area
}
let myRectangle = Rectangle(width: 5, height: 10)
print(calculateArea(of: myRectangle)) // 50
let mySquare = Square(side: 5)
// Se asume que esto es un rectángulo de 5x5 con área 25.
// Pero al usarlo en una función que espera un Rectangle,
// su comportamiento puede ser inesperado si se cambian el ancho o la altura
// antes de llamar a calculateArea, ya que Square cambia ambos lados simultáneamente.
// En este ejemplo, si no se cambian las propiedades después de la inicialización,
// el resultado será 25, pero si, por ejemplo, se hace mySquare.width = 10
// antes de llamar a calculateArea, su área será 100, lo cual puede ser inesperado para el código que trabaja con Rectangle.
print(calculateArea(of: mySquare)) // 25
En el ejemplo, Square viola LSP, ya que cambiar una dimensión (width o height) también cambia la otra. Si usamos un objeto Square donde se esperaba un Rectangle, esto puede llevar a comportamientos inesperados, ya que el código que trabaja con Rectangle puede suponer la posibilidad de cambiar las lados de forma independiente.
Cumplimiento de LSP:
Para cumplir con LSP en este caso, se puede dividir la jerarquía o usar composición en lugar de herencia para Square. Por ejemplo, introducir una interfaz o protocolo común para figuras que tengan área, y implementarlo en Rectangle y Square.
protocol Shape {
var area: Double { get }
}
class Rectangle: Shape {
var width: Double
var height: Double
init(width: Double, height: Double) {
self.width = width
self.height = height
}
var area: Double {
return width * height
}
}
class Square: Shape {
var side: Double
init(side: Double) {
self.side = side
}
var area: Double {
return side * side
}
}
func calculateShapeArea(of shape: Shape) -> Double {
return shape.area
}
let myShapeRectangle: Shape = Rectangle(width: 5, height: 10)
print(calculateShapeArea(of: myShapeRectangle)) // 50
let myShapeSquare: Shape = Square(side: 5)
print(calculateShapeArea(of: myShapeSquare)) // 25
Ahora, Square y Rectangle implementan el protocolo Shape, y podemos usar objetos de ambas clases donde se espere un Shape, sin violar el comportamiento esperado.