Sobes.tech
Junior

Mille eest vastutab täht 'L' SOLID põhimõtetes?

sobes.tech AI

Vastus AI-lt

Liskovi asenduspõhimõte (Liskov Substitution Principle).

Selle põhimõtte kohaselt peavad programmis olevad objektid olema asendatavad nende alamklasside eksemplaridega ilma programmi õigsust muutmata.

Teisisõnu, kui klass B on klassi A alamklass, siis võib iga A tüüpi objekt programmis olla asendatud B tüüpi objektiga ning programm jätkab korrektset tööd.

See põhimõte aitab luua paindlikumat ja muutustele vastupidavamat arhitektuuri, minimeerides kõrvaltoimeid pärilikkuse kasutamisel.

LSP rikkumine:

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 { // Ruut on ristküliku alamklass
    override var width: Double {
        didSet {
            height = width // Laiuse muutmine muudab ka kõrgust
        }
    }

    override var height: Double {
        didSet {
            width = height // Kõrguse muutmine muudab ka laiust
        }
    }

    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)
// Oletame, et see on 5x5 ristkülik, mille pindala on 25.
// Kuid kasutades funktsioonis, mis ootab `Rectangle`-i,
// võib selle käitumine olla ettearvamatu, kui muuta laiust või kõrgust
// enne `calculateArea` väljakutset, kuna `Square` muudab mõlemad küljed korraga.
// Selles näites, kui mitte muuta omadusi pärast initsialiseerimist,
// on tulemus 25, kuid kui näiteks seame mySquare.width = 10
// enne `calculateArea` väljakutset, muutub selle pindala 100-ks, mis võib olla
// ootamatu `Rectangle`-iga töötavale koodile.
print(calculateArea(of: mySquare)) // 25

Selles näites rikub Square LSP-d, kuna ühe mõõtme (width või height) muutmine muudab ka teise. Kui kasutame Square objekti seal, kus oodatakse Rectangle-i, võib see viia ootamatu käitumiseni, kuna Rectangle-i kood võib eeldada, et küljed saavad muutuda sõltumatult.

LSP järgimine:

Selleks, et järgida LSP-d selles olukorras, võib jagada hierarhia või kasutada kompositsiooni mantoimise asemel Square-i jaoks. Näiteks võib luua ühise liidese või protokolli kujutiste jaoks, millel on pindala, ning rakendada seda Rectangle ja Square-is.

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

Nüüd rakendavad Square ja Rectangle ühise protokolli Shape, ning saame kasutada mõlema klassi objekte seal, kus oodatakse Shape-i, ilma et rikuksime oodatavat käitumist.