﻿import math
from abc import ABC, abstractmethod

# Klasa abstrakcyjna Figura, dziedzicząca po ABC (Abstract Base Class).
# Służy jako szablon (kontrakt) dla wszystkich konkretnych figur w systemie.
class Figura(ABC):
    
    # Dekorator @abstractmethod wymusza na klasach pochodnych
    # zaimplementowanie tej metody. Bez niej podklasa również będzie traktowana jako abstrakcyjna.
    @abstractmethod
    def oblicz_pole(self):
        """
        Metoda abstrakcyjna do obliczania pola powierzchni figury.
        Z założenia nie posiada implementacji w klasie bazowej (użyto instrukcji pass).
        """
        pass

# Klasa pochodna reprezentująca Koło.
class Kolo(Figura):
    def __init__(self, promien):
        self.promien = promien
        
    # Implementacja metody abstrakcyjnej jest tutaj obowiązkowa.
    # Jeśli byśmy jej nie zaimplementowali, próba stworzenia instancji Kolo zgłosiłaby błąd.
    def oblicz_pole(self):
        """
        Oblicza pole koła używając wzoru pi * r^2.
        Użyto dokładnej wartości pi z modułu math.
        """
        return math.pi * (self.promien ** 2)

# Klasa pochodna reprezentująca Prostokąt.
class Prostokat(Figura):
    def __init__(self, szerokosc, wysokosc):
        self.szerokosc = szerokosc
        self.wysokosc = wysokosc
        
    # Ponownie, implementacja metody abstrakcyjnej.
    def oblicz_pole(self):
        """
        Oblicza pole prostokąta.
        """
        return self.szerokosc * self.wysokosc

# Opcjonalnie: Klasa, która nie implementuje abstrakcyjnej metody, aby pokazać błąd.
class NiekompletnaFigura(Figura):
    pass

if __name__ == "__main__":
    # Testowanie poprawnie zaimplementowanych klas
    kolo = Kolo(5)
    print(f"Pole koła: {kolo.oblicz_pole():.4f}")
    
    prostokat = Prostokat(4, 6)
    print(f"Pole prostokąta: {prostokat.oblicz_pole()}")
    
    print("-" * 40)
    
    # Próba utworzenia instancji klasy abstrakcyjnej
    # Python powinien rzucić TypeError, zabezpieczając nas przed utworzeniem niepełnego obiektu.
    try:
        figura = Figura()
    except TypeError as e:
        print(f"Złapano oczekiwany błąd przy tworzeniu instancji Figura: {e}")

    # Próba utworzenia instancji podklasy, która nie zaimplementowała metody abstrakcyjnej
    try:
        zla_figura = NiekompletnaFigura()
    except TypeError as e:
        print(f"Złapano oczekiwany błąd przy tworzeniu instancji NiekompletnaFigura: {e}")
