Do que é responsável a letra 'L' nos princípios SOLID?
sobes.tech IA
Resposta da IA
Princípio de substituição de Barbara Liskov (**Princípio de Substituição de Liskov).
De acordo com este princípio, os objetos num programa devem ser substituíveis por instâncias dos seus subtipos sem alterar a correção do programa.
Em outras palavras, se a classe B é um subtipo da classe A, então qualquer objeto do tipo A no programa pode ser substituído por um objeto do tipo B, e o programa continuará a funcionar corretamente.
Este princípio ajuda a criar uma arquitetura mais flexível e resistente a mudanças, minimizando efeitos secundários ao trabalhar com herança.
Violação do 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 { // O quadrado é um subtipo de retângulo
override var width: Double {
didSet {
height = width // Alterar a largura também altera a altura
}
}
override var height: Double {
didSet {
width = height // Alterar a altura também altera a largura
}
}
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)
// Assume-se que é um retângulo 5x5 com área 25.
// Mas ao usá-lo numa função que espera um Rectangle,
// o seu comportamento pode ser inesperado se alterar a largura ou a altura
// antes de chamar calculateArea, pois Square altera ambos os lados ao mesmo tempo.
// Neste exemplo, se não alterar as propriedades após a inicialização,
// o resultado será 25, mas se, por exemplo, fizer mySquare.width = 10
// antes de chamar calculateArea, a sua área será 100, o que pode
// ser inesperado para o código que trabalha com Rectangle.
print(calculateArea(of: mySquare)) // 25
No exemplo, Square viola o LSP porque alterar uma dimensão (width ou height) também altera a outra. Se usarmos um objeto Square onde se esperava um Rectangle, isso pode levar a comportamentos inesperados, pois o código que trabalha com Rectangle pode assumir a possibilidade de alterar os lados de forma independente.
Conformidade com o LSP:
Para cumprir o LSP neste caso, pode-se dividir a hierarquia ou usar composição em vez de herança para Square. Por exemplo, introduzir uma interface ou protocolo comum para figuras que tenham área, e implementá-lo em Rectangle e 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
Agora, Square e Rectangle implementam um protocolo comum Shape, e podemos usar objetos de ambas as classes onde se espera um Shape, sem violar o comportamento esperado.