Už ką atsako raidė 'L' SOLID principuose?
sobes.tech AI
Atsakymas iš AI
Liskovo pakaitumo principas (Liskov Substitution Principle).
Pagal šį principą, programoje objektai turi būti keičiami jų pogrupių egzemplioriais be programos teisingumo pakeitimo.
Kitaip tariant, jei klasė B yra klasės A pogrupis, tada bet kuris A tipo objektas programoje gali būti pakeistas B tipo objektu, ir programa toliau veiks teisingai.
Šis principas padeda kurti lankstesnę ir atsparią keitimams architektūrą, sumažindamas šalutinį poveikį paveldėjimo naudojime.
LSP pažeidimas:
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 { // Kvadratas yra stačiakampio pogrupis
override var width: Double {
didSet {
height = width // Svorio keitimas taip pat keičia aukštį
}
}
override var height: Double {
didSet {
width = height // Aukščio keitimas taip pat keičia plotį
}
}
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)
// Tarkime, tai yra 5x5 stačiakampis su plotu 25.
// Tačiau naudojant funkcijoje, kuri tikisi `Rectangle`,
// jo elgsena gali būti nenuspėjama, jei pakeisti plotį ar aukštį
// prieš kvietimą `calculateArea`, nes `Square` keičia abi puses vienu metu.
// Šiame pavyzdyje, jei nekeičiame savybių po inicializacijos,
// rezultatas bus 25, tačiau jei, pavyzdžiui, padarysime mySquare.width = 10
// prieš kvietimą `calculateArea`, jo plotas taps 100, kas gali būti
// netikėta `Rectangle`-s veikiančiam kodui.
print(calculateArea(of: mySquare)) // 25
Šiame pavyzdyje Square pažeidžia LSP, nes vieno matmens (width arba height) keitimas taip pat keičia kitą. Jei naudojame Square objektą ten, kur tikėtasi Rectangle, tai gali sukelti netikėtą elgesį, nes Rectangle-s kodas gali manyti, kad pusių keitimas yra nepriklausomas.
LSP laikymasis:
Kad laikytumėmės LSP šiuo atveju, galime atskirti hierarchiją arba naudoti kompoziciją vietoje paveldėjimo Square atveju. Pavyzdžiui, galima įvesti bendrą sąsają arba protokolą figūroms, kurios turi plotą, ir įgyvendinti jį Rectangle ir 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
Dabar Square ir Rectangle įgyvendina bendrą protokolą Shape, ir galime naudoti objektus abiejų klasių ten, kur tikimasi Shape, be pažeidimo numatyto elgesio.