Sobes.tech
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.