Senior
Wyjaśnij zasadę podstawiania Barbary Liskov.
sobes.tech AI
Odpowiedź od AI
Jeśli w programie S jest podtypem T, to obiekty typu T w programie mogą być zastępowane obiektami typu S bez naruszania funkcjonalności programu.
Kluczowe punkty:
- Zachowanie zachowania: Podtyp powinien zachowywać się tak samo jak jego typ bazowy, z punktu widzenia zewnętrznego obserwatora.
- Inwarianty: Inwarianty klasy bazowej powinny być zachowane w podklasach.
- Postwarunki: Postwarunki (warunki, które muszą być prawdziwe po wykonaniu metody) podklasy powinny być takie same lub silniejsze niż postwarunki klasy bazowej.
- Prewarunki: Prewarunki (warunki, które muszą być prawdziwe przed wykonaniem metody) podklasy powinny być takie same lub słabsze niż prewarunki klasy bazowej.
Przykład w Pythonie:
class Rectangle:
def __init__(self, width, height):
self._width = width
self._height = height
def set_width(self, width):
self._width = width
def set_height(self, height):
self._height = height
def area(self):
return self._width * self._height
class Square(Rectangle):
def __init__(self, side):
super().__init__(side, side)
def set_width(self, width):
self._width = width
self._height = width # Naruszenie zasady: zmiana szerokości zmienia również wysokość
def set_height(self, height):
self._width = height # Naruszenie zasady: zmiana wysokości zmienia również szerokość
self._height = height
# Przykład użycia naruszający LSP:
def enlarge_rectangle(rectangle):
rectangle.set_width(rectangle._width + 1)
rectangle.set_height(rectangle._height + 1)
return rectangle.area()
rect = Rectangle(2, 3)
print(f"Powierzchnia po enlarge_rectangle(rect): {enlarge_rectangle(rect)}") # Oczekiwane 12
square = Square(2)
print(f"Powierzchnia po enlarge_rectangle(square): {enlarge_rectangle(square)}") # Oczekiwane 9, ale z powodu set_width/set_height w Square będzie 16. Naruszenie!
Ten princip jest ważny dla zapewnienia poprawności dziedziczenia i polimorfizmu, czyniąc kod bardziej niezawodnym i przewidywalnym.