Ҳарфи '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
// яго плошча стане 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, без парушэння чаканага паводзінаў.