Sobes.tech
Junior

რას პასუხს აგებს ასო 'L' SOLID-ის პრინციპებში?

sobes.tech AI

პასუხი AI-სგან

ბარბარა ლისკოვის ჩანაცვლების პრინციპი (Liskov Substitution Principle).

ამ პრინციპის მიხედვით, პროგრამაში ობიექტები უნდა იყოს ჩანაცვლებადი მათი ქვესახეების მაგალითებით ისე, რომ პროგრამის სწორება არ შეცვლილიყო.

სიტყვით რომ ვთქვათ, თუ კლასი B არის კლასი A-ს ქვესახე, მაშინ ნებისმიერი ობიექტი ტიპის A პროგრამაში შეიძლება შეიცვალოს ობიექტით ტიპის B, და პროგრამა გააგრძელებს სწორად მუშაობას.

ეს პრინციპი ეხმარება უფრო მოქნილი და ცვლილებებზე მდგრადი არქიტექტურის შექმნაში, მინიმუმამდე ამცირებს გვერდით ეფექტებს მემკვიდრეობის გამოყენებისას.

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 { // კვადრატი არის მართკუთხედის ქვესახე
    override var width: Double {
        didSet {
            height = width // სიგანის ცვლილება ასევე ცვლის სიმაღლეს
        }
    }

    override var height: Double {
        didSet {
            width = height // სიმაღლის ცვლილება ასევე ცვლის სიგანს
        }
    }

    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)
// ვივარაუდოთ, რომ ეს არის 5x5 მართკუთხედის ფართობით 25.
// მაგრამ ფუნქციაში გამოყენებისას, სადაც ელოდება `Rectangle`-ს,
// მისი ქცევა შეიძლება იყოს გაურკვეველი, თუ სიგანის ან სიმაღლის ცვლილება მოხდება
// `calculateArea`-ის გამოძახებამდე, რადგან `Square` ორივე მხარეს ერთდროულად ცვლის.
// ამ მაგალითში, თუ არ შეიცვალა თვისებები ინიციალიზაციის შემდეგ,
// შედეგი იქნება 25, მაგრამ თუ მაგალითად, გავაკეთებთ mySquare.width = 10
// `calculateArea`-ის გამოძახებამდე, მისი ფართობი გახდება 100, რაც შეიძლება იყოს
// გაუკვირვებელი `Rectangle`-თან მუშაობს კოდისათვის.
print(calculateArea(of: mySquare)) // 25

ამ მაგალითში Square არღვევს LSP-ს, რადგან ერთი ზომის (width ან height) ცვლილება ასევე ცვლის მეორე. თუ ვიყენებთ Square ობიექტს იმ ადგილას, სადაც ელოდებოდათ Rectangle, ეს შეიძლება გამოიწვიოს გაურკვეველი ქცევა, რადგან Rectangle-თან მუშაობს კოდი შეიძლება ფიქრობდეს დამოუკიდებელ ცვლილებაზე.

LSP-ის დაცვა:

ამ შემთხვევისთვის, LSP-ის დაცვაში, შეიძლება განვაგრძოთ ჰიერქხია ან გამოიყენოთ კომპოზიცია მემკვიდრეობის ნაცვლად Square-ისთვის. მაგალითად, შევქმნათ საერთო ინტერფეისი ან პროტოკოლი ფიგურებისთვის, რომლებიც აქვთ ფართობი, და განვახორციელოთ იგი Rectangle და 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

ახლა Square და Rectangle ახორციელებენ საერთო პროტოკოლს Shape, და შეგვიძლია გამოვიყენოთ ორივე კლასი იმ ადგილას, სადაც ელოდება Shape, ისე, რომ არ ვარღვევთ მოსალოდნელ ქცევას.