﻿# OOP_LAB_4_zad_03.py
"""
Rozwiązanie zadania 3: Problem diamentowy (MRO w praktyce)
"""

class Osoba:
    """
    Klasa najwyższego rzędu, wspólny przodek dla wszystkich elementów hierarchii.
    """
    def __init__(self):
        # Sprawdzamy kiedy ten konstruktor zostanie uruchomiony.
        # W problemie diamentowym MRO gwarantuje wywołanie go tylko raz.
        print("[Inicjalizacja Osoba]")

    def przedstaw_sie(self):
        """
        Zasadniczy komunikat identyfikacyjny z klasy bazowej.
        """
        print("Jestem Osobą.")

class Student(Osoba):
    """
    Pierwsza z klas pośrednich. Dziedziczy po Osoba.
    """
    def __init__(self):
        print("[Inicjalizacja Student]")
        # Konstruktor w klasie dziedziczącej po wywołaniu super() przekazuje wykonanie dalej wg algorytmu MRO.
        super().__init__()

    def przedstaw_sie(self):
        print("Jestem Studentem.")
        # super() zapewnia poprawny łańcuch wywołań w MRO.
        super().przedstaw_sie()

class Pracownik(Osoba):
    """
    Druga z klas pośrednich. Również dziedziczy po Osoba.
    """
    def __init__(self):
        print("[Inicjalizacja Pracownik]")
        super().__init__()

    def przedstaw_sie(self):
        print("Jestem Pracownikiem.")
        # Wywołanie super().przedstaw_sie() popycha wywołanie wyżej (lub na boki) wg MRO.
        super().przedstaw_sie()

class StudentPracownik(Student, Pracownik):
    """
    Klasa końcowa łącząca dwie role. Dziedziczy wielokrotnie.
    Tworzy strukturę "diamentu" z klasą Osoba jako korzeniem.
    """
    def __init__(self):
        print("[Inicjalizacja StudentPracownik]")
        # To wywołanie odpali łańcuch C3 Linearization (algorytm MRO),
        # który po kolei zainicjalizuje Studenta, następnie Pracownika,
        # a na samym końcu wywoła wspólnego przodka - Osobę, zapobiegając duplikacji!
        super().__init__()

    def przedstaw_sie(self):
        # Tutaj wywołanie super().przedstaw_sie() po prostu przechodzi do następnej klasy w MRO,
        # czyli do 'Student', następnie stamtąd do 'Pracownik', a na końcu z Pracownika do 'Osoba'.
        super().przedstaw_sie()


if __name__ == "__main__":
    print("--- Testowanie Problemu Diamentowego i MRO ---")
    
    print("Tworzenie instancji sp = StudentPracownik():")
    # Zauważ, że konstruktor klasy Osoba jest wywoływany tylko JEDEN RAZ!
    sp = StudentPracownik()
    
    print("\nWywołanie sp.przedstaw_sie():")
    # Python dzięki zastosowaniu MRO wie, aby połączyć wywołania w płaską listę,
    # eliminując ryzyko kilkukrotnego wywołania bazowych metod.
    sp.przedstaw_sie()
    
    print("\nSprawdzenie ścieżki poszukiwania metod (MRO):")
    # MRO to sposób, w jaki Python ustala kolejność dziedziczenia w grafie.
    # Wynik z mro() pokaże po kolei klasy: StudentPracownik -> Student -> Pracownik -> Osoba -> object
    print(StudentPracownik.mro())
    
    # Dodatkowy test - po zmianie kolejności rodziców MRO ulegnie zmianie
    class PracownikStudent(Pracownik, Student):
        pass
    
    print("\nMRO dla klasy z inną kolejnością dziedziczenia (PracownikStudent):")
    print(PracownikStudent.mro())
