Dziedziczenie w Perl realizowane jest za pomocą tablicy @ISA, która wskazuje, z jakich pakietów (klas) dziedziczy obecny pakiet. Nie jest to tradycyjne OO, jak w wielu innych językach, a raczej dynamiczne podstawienie rodziców w trakcie wyszukiwania metod.
W wczesnych wersjach Perla nie było wbudowanego podejścia obiektowego. Aby wspierać dziedziczenie, wprowadzono tablicę @ISA (ISA = Is A), w której wymienia się klasy rodzicielskie. Perl najpierw szuka metod w klasie samego obiektu, następnie w kolejności w rodzicach, co daje pewną elastyczność, ale rodzi swoje szczególne cechy.
Sposoby dziedziczenia przez @ISA łatwo łamią enkapsulację. Ponadto, wielopoziomowe (wielokrotne) dziedziczenie wymaga ostrożnego traktowania kolejności rodziców, aby uniknąć nieoczekiwanych konfliktów metod. Ważnym punktem staje się kolejność wyszukiwania metod (Method Resolution Order), która nie zawsze jest oczywista, szczególnie przy użyciu modułów CPAN (na przykład klas z Moose, base lub parent).
Do prostego dziedziczenia w Perl używa się deklaracji tablicy @ISA:
package Parent; sub hello { print "Cześć z rodzica! "; } package Child; our @ISA = ('Parent'); Child::hello(); # Wyświetli: Cześć z rodzica!
W rzeczywistych projektach często stosuje się pragma base lub parent dla uproszczenia pracy z dziedziczeniem i większego bezpieczeństwa.
@ISA.Czy pragma BASE lub użycie tablicy @ISA może dodać metody rodzica do klasy potomnej po uruchomieniu programu?
Nie, Perl pozwala na dziedziczenie w czasie kompilacji skryptu, a nie w czasie wykonywania. Jeśli zmiany w @ISA zachodzą podczas wykonywania, w rzeczywistości wpłyną tylko na niektóre już zadeklarowane obiekty, co może powodować dziwne problemy.
package Parent; sub hello { print "rodzic "; } package Child; our @ISA = ('Parent'); # po stworzeniu obiektów nie zaleca się zmiany @ISA
Co się stanie, jeśli zadeklarujesz tę samą metodę w kilku klasach rodzicielskich w @ISA?
Zostanie wywołana pierwsza znaleziona w kolejności podanej w @ISA. Może to prowadzić do nieoczekiwanego zachowania, szczególnie przy wielokrotnym dziedziczeniu.
package Base1; sub hello { print "Base1 "; } package Base2; sub hello { print "Base2 "; } package Derived; our @ISA = ('Base1', 'Base2'); Derived::hello(); # Wyświetli: Base1
Czy można dynamicznie dodać klasę do @ISA i uzyskać dostęp do jej metod?
Tak, można, ale jest to skrajnie niezalecane, ponieważ burzy strukturę programu, może prowadzić do błędów w rozwiązywaniu metod i błędów podczas wykonywania.
@ISA w czasie wykonywania programuparent/base, co obniża utrzymywalnośćW projekcie, aby dodać funkcjonalność do klas-protokółów, ręcznie w cyklu zmieniają tablicę @ISA, aby dziedziczyć metody z dynamicznie dołączanych modułów w zależności od warunków.
Zalety:
Wady:
Aby rozszerzyć klasę, używają pragmy parent, ściśle kontrolując kolejność rodziców i wyraźnie definiując metody, które mogą być nadpisywane.
Zalety:
Wady: