Za co odpovídá písmeno 'L' v principech SOLID?
sobes.tech AI
Odpověď od AI
Princip Liskovovy substituce (Liskovovo pravidlo substituce).
Podle tohoto pravidla by objekty v programu měly být nahraditelné instancemi svých podtříd bez změny správnosti programu.
Jinými slovy, pokud třída B je podtřídou třídy A, pak jakýkoli objekt typu A v programu může být nahrazen objektem typu B, a program bude nadále správně fungovat.
Toto pravidlo pomáhá vytvářet flexibilnější a odolnější architekturu, minimalizuje vedlejší efekty při práci s dědičností.
Porušení 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 { // Čtverec je podtřídou obdélníku
override var width: Double {
didSet {
height = width // Změna šířky také mění výšku
}
}
override var height: Double {
didSet {
width = height // Změna výšky také mění šířku
}
}
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)
// Předpokládáme, že je to obdélník 5x5 s plochou 25.
// Ale při použití ve funkci, která očekává Rectangle,
// může být jeho chování nepředvídatelné, pokud změníme šířku nebo výšku
// před voláním calculateArea, protože Square mění obě strany současně.
// V tomto příkladu, pokud nezměníme vlastnosti po inicializaci,
// bude výsledek 25, ale pokud například nastavíme mySquare.width = 10
// před voláním calculateArea, jeho plocha bude 100, což může být neočekávané.
print(calculateArea(of: mySquare)) // 25
V příkladu Square porušuje LSP, protože změna jednoho rozměru (width nebo height) také změní druhý. Pokud použijeme objekt Square tam, kde se očekává Rectangle, může dojít k neočekávanému chování, protože kód pracující s Rectangle může předpokládat možnost nezávislé změny stran.
Dodržení LSP:
Abychom dodrželi LSP v tomto případě, můžeme hierarchii rozdělit nebo místo dědičnosti použít kompozici pro Square. Například zavést společné rozhraní nebo protokol pro tvary, které mají plochu, a implementovat ho v Rectangle a 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
Nyní Square a Rectangle implementují společný protokol Shape, a můžeme používat objekty obou tříd tam, kde je očekáván Shape, bez narušení očekávaného chování.