Sobes.tech
Junior

Ի՞նչ է պատասխանատու 'L' տառը SOLID սկզբունքներում։

sobes.tech AI

Պատասխան AI-ից

Լիսկովի փոխարինման սկզբունք (Liskov փոխարինման սկզբունք):

Այս սկզբունքի համաձայն, ծրագրում գտնվող օբյեկտները պետք է փոխարինելի լինեն իրենց ենթատեսակների օրինակներով առանց ծրագրի ճիշտ գործելու փոփոխության:

Այլ կերպ ասած, եթե 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` դնենք,
// նրա մակերեսը կլինի 100, ինչը կարող է լինել անսպասելի `Rectangle`-ով աշխատող կոդի համար:
print(calculateArea(of: mySquare)) // 25

Նշված օրինակով, Square խախտում է LSP-ը, քանի որ մեկ չափի փոփոխությունը (width կամ height) նաև փոխում է մյուսը:

LSP պահպանելու համար:

Այս դեպքում, կարելի է բաժանել ժառանգության հիերարխիան կամ օգտագործել կոմպոզիցիա ժառանգության փոխարեն 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, առանց սպասվող վարքագծի խախտման:

Նշում:

Այս թարգմանությունները նպատակ ունեն բացատրել Liskov-ի փոխարինման սկզբունքը տարբեր լեզուներով, և չեն փոխարինում կամ փոխարինում են բնօրինակի բովանդակությանը։