﻿from abc import ABC, abstractmethod

# Klasa abstrakcyjna Pojazd, definiująca wymagane właściwości (atrybuty)
# za pomocą połączenia dekoratorów @property i @abstractmethod.
class Pojazd(ABC):
    
    # Uwaga na kolejność dekoratorów! 
    # @property musi być zdefiniowane wyżej (dalej od definicji metody) niż @abstractmethod.
    @property
    @abstractmethod
    def predkosc_max(self):
        """
        Abstrakcyjna właściwość - każda podklasa musi posiadać 
        sprecyzowaną prędkość maksymalną (zwracaną przez getter).
        """
        pass
        
    @property
    @abstractmethod
    def liczba_kol(self):
        """
        Druga abstrakcyjna właściwość - każda podklasa musi 
        określić liczbę kół.
        """
        pass

# Klasa Samochod poprawnie implementująca wymagane właściwości.
class Samochod(Pojazd):
    
    @property
    def predkosc_max(self):
        # Konkretna implementacja właściwości.
        # Właściwości zachowują się jak zmienne podczas odczytu.
        return 200
        
    @property
    def liczba_kol(self):
        return 4

# Klasa Motocykl również implementująca kontrakt.
class Motocykl(Pojazd):
    
    @property
    def predkosc_max(self):
        return 280
        
    @property
    def liczba_kol(self):
        return 2

# Klasa Rower, która nie implementuje właściwości (służy do demonstracji błędu).
class Rower(Pojazd):
    pass


if __name__ == "__main__":
    # Testujemy poprawne obiekty
    s = Samochod()
    print(f"Samochód ma {s.liczba_kol} koła i osiąga {s.predkosc_max} km/h.")
    
    m = Motocykl()
    print(f"Motocykl ma {m.liczba_kol} koła i osiąga {m.predkosc_max} km/h.")
    
    print("-" * 40)
    
    # Próba utworzenia Roweru, który jest klasą abstrakcyjną ze względu
    # na brak implementacji właściwości predkosc_max i liczba_kol.
    try:
        r = Rower()
    except TypeError as e:
        print(f"Złapano oczekiwany błąd przy tworzeniu instancji Rower: {e}")
        print("Wyjaśnienie: Wymuszanie właściwości (properties) jest bezpieczniejsze, "
              "ponieważ pilnuje spójności struktury atrybutów obiektu już w chwili "
              "jego inicjalizacji, a nie dopiero przy próbie odczytu zmiennej.")
