Programowanie obiektowe w PERL

Przeanalizowaliśmy już odwołania w anonimowych tablicach i hashach Perla i Perla. Koncepcja zorientowana obiektowo w Perlu opiera się w dużej mierze na odwołaniach oraz anonimowych tablicach i skrótach. Zacznijmy uczyć się podstawowych pojęć związanych z obiektami w języku Perl.

Podstawy obiektów

Istnieją trzy główne terminy, wyjaśnione z punktu widzenia sposobu, w jaki Perl obsługuje obiekty. Warunki to obiekt, klasa i metoda.

  • Na objectw Perlu jest jedynie odniesieniem do typu danych, który wie, do jakiej klasy należy. Obiekt jest przechowywany jako odniesienie w zmiennej skalarnej. Ponieważ skalar zawiera tylko odniesienie do obiektu, ten sam skalar może zawierać różne obiekty w różnych klasach.

  • ZA class w Perlu jest pakiet zawierający odpowiednie metody wymagane do tworzenia obiektów i manipulowania nimi.

  • ZA methodw Perlu jest podprogram zdefiniowany w pakiecie. Pierwszym argumentem metody jest odwołanie do obiektu lub nazwa pakietu, w zależności od tego, czy metoda wpływa na bieżący obiekt, czy na klasę.

Perl udostępnia bless() funkcja, która służy do zwracania odniesienia, które ostatecznie staje się obiektem.

Definiowanie klasy

Definiowanie klasy w Perlu jest bardzo proste. Klasa odpowiada pakietowi Perla w jego najprostszej formie. Aby utworzyć klasę w Perlu, najpierw budujemy pakiet.

Pakiet jest samodzielną jednostką zmiennych zdefiniowanych przez użytkownika i podprogramów, których można używać wielokrotnie.

Pakiety Perla zapewniają oddzielną przestrzeń nazw w programie Perla, która utrzymuje podprogramy i zmienne niezależne od konfliktów z tymi w innych pakietach.

Aby zadeklarować klasę o nazwie Person w Perlu, robimy -

package Person;

Zakres definicji pakietu rozciąga się do końca pliku lub do momentu napotkania innego słowa kluczowego pakietu.

Tworzenie i używanie obiektów

Do stworzenia instancji klasy (obiektu) potrzebujemy konstruktora obiektów. Ten konstruktor jest metodą zdefiniowaną w pakiecie. Większość programistów wybiera nową nazwę tej metody konstruktora obiektów, ale w Perlu możesz użyć dowolnej nazwy.

Możesz użyć dowolnego rodzaju zmiennej Perla jako obiektu w Perlu. Większość programistów Perla wybiera odwołania do tablic lub skrótów.

Stwórzmy nasz konstruktor dla naszej klasy Person przy użyciu skrótu Perl. Tworząc obiekt, musisz dostarczyć konstruktor, który jest procedurą wewnątrz pakietu, która zwraca odwołanie do obiektu. Odniesienie do obiektu jest tworzone przez błogosławieństwo odniesienia do klasy pakietu. Na przykład -

package Person;
sub new {
   my $class = shift;
   my $self = {
      _firstName => shift,
      _lastName  => shift,
      _ssn       => shift,
   };
   # Print all the values just for clarification.
   print "First Name is $self->{_firstName}\n";
   print "Last Name is $self->{_lastName}\n";
   print "SSN is $self->{_ssn}\n";
   bless $self, $class;
   return $self;
}

Zobaczmy teraz, jak stworzyć obiekt.

$object = new Person( "Mohammad", "Saleem", 23234345);

Możesz użyć prostego skrótu w swoim konstruktorze, jeśli nie chcesz przypisywać żadnej wartości do żadnej zmiennej klasy. Na przykład -

package Person;
sub new {
   my $class = shift;
   my $self = {};
   bless $self, $class;
   return $self;
}

Definiowanie metod

Inne języki zorientowane obiektowo mają koncepcję bezpieczeństwa danych, aby uniemożliwić programiście bezpośrednią zmianę danych obiektowych i zapewniają metody dostępu do modyfikowania danych obiektowych. Perl nie ma prywatnych zmiennych, ale nadal możemy używać koncepcji metod pomocniczych do manipulowania danymi obiektu.

Pozwala zdefiniować metodę pomocniczą, aby uzyskać imię osoby -

sub getFirstName {
   return $self->{_firstName};
}

Kolejna funkcja pomocnicza do ustawienia imienia osoby -

sub setFirstName {
   my ( $self, $firstName ) = @_;
   $self->{_firstName} = $firstName if defined($firstName);
   return $self->{_firstName};
}

Przyjrzyjmy się teraz kompletnemu przykładowi: Zachowaj pakiet Person i funkcje pomocnicze w pliku Person.pm.

#!/usr/bin/perl 

package Person;

sub new {
   my $class = shift;
   my $self = {
      _firstName => shift,
      _lastName  => shift,
      _ssn       => shift,
   };
   # Print all the values just for clarification.
   print "First Name is $self->{_firstName}\n";
   print "Last Name is $self->{_lastName}\n";
   print "SSN is $self->{_ssn}\n";
   bless $self, $class;
   return $self;
}
sub setFirstName {
   my ( $self, $firstName ) = @_;
   $self->{_firstName} = $firstName if defined($firstName);
   return $self->{_firstName};
}

sub getFirstName {
   my( $self ) = @_;
   return $self->{_firstName};
}
1;

Skorzystajmy teraz z obiektu Person w pliku Employer.pl w następujący sposób -

#!/usr/bin/perl

use Person;

$object = new Person( "Mohammad", "Saleem", 23234345);
# Get first name which is set using constructor.
$firstName = $object->getFirstName();

print "Before Setting First Name is : $firstName\n";

# Now Set first name using helper function.
$object->setFirstName( "Mohd." );

# Now get first name set by helper function.
$firstName = $object->getFirstName();
print "Before Setting First Name is : $firstName\n";

Kiedy wykonujemy powyższy program, daje on następujący wynik -

First Name is Mohammad
Last Name is Saleem
SSN is 23234345
Before Setting First Name is : Mohammad
Before Setting First Name is : Mohd.

Dziedzictwo

Programowanie obiektowe ma bardzo dobrą i przydatną koncepcję zwaną dziedziczeniem. Dziedziczenie oznacza po prostu, że właściwości i metody klasy nadrzędnej będą dostępne dla klas potomnych. Nie musisz więc ciągle pisać tego samego kodu, możesz po prostu odziedziczyć klasę nadrzędną.

Na przykład możemy mieć klasę Employee, która dziedziczy po Person. Nazywa się to relacją „isa”, ponieważ pracownik to osoba. Perl ma specjalną zmienną @ISA, która pomaga w tym. @ISA zarządza dziedziczeniem (metody).

Poniżej przedstawiono ważne kwestie, które należy wziąć pod uwagę podczas korzystania z dziedziczenia -

  • Perl przeszukuje klasę określonego obiektu pod kątem podanej metody lub atrybutu, tj. Zmiennej.

  • Perl przeszukuje klasy zdefiniowane w tablicy @ISA klasy obiektów.

  • Jeśli w krokach 1 lub 2 nie zostanie znaleziona żadna metoda, Perl używa procedury AUTOLOAD, jeśli została znaleziona w drzewie @ISA.

  • Jeśli nadal nie można znaleźć pasującej metody, Perl szuka metody w klasie (pakiecie) UNIVERSAL, która jest częścią standardowej biblioteki Perla.

  • Jeśli metoda nadal nie została znaleziona, Perl poddaje się i zgłasza wyjątek w czasie wykonywania.

Aby więc utworzyć nową klasę Employee, która będzie dziedziczyć metody i atrybuty z naszej klasy Person, po prostu kodujemy w następujący sposób: Zachowaj ten kod w Employee.pm.

#!/usr/bin/perl

package Employee;
use Person;
use strict;
our @ISA = qw(Person);    # inherits from Person

Teraz klasa Employee ma wszystkie metody i atrybuty odziedziczone z klasy Person i możesz ich użyć w następujący sposób: Użyj pliku main.pl, aby ją przetestować -

#!/usr/bin/perl

use Employee;

$object = new Employee( "Mohammad", "Saleem", 23234345);
# Get first name which is set using constructor.
$firstName = $object->getFirstName();

print "Before Setting First Name is : $firstName\n";

# Now Set first name using helper function.
$object->setFirstName( "Mohd." );

# Now get first name set by helper function.
$firstName = $object->getFirstName();
print "After Setting First Name is : $firstName\n";

Kiedy wykonujemy powyższy program, daje on następujący wynik -

First Name is Mohammad
Last Name is Saleem
SSN is 23234345
Before Setting First Name is : Mohammad
Before Setting First Name is : Mohd.

Zastępowanie metody

Klasa potomna Employee dziedziczy wszystkie metody z klasy nadrzędnej Person. Ale jeśli chcesz zastąpić te metody w swojej klasie podrzędnej, możesz to zrobić, podając własną implementację. Możesz dodać swoje dodatkowe funkcje w klasie podrzędnej lub możesz dodać lub zmodyfikować funkcjonalność istniejących metod w klasie nadrzędnej. Można to zrobić w następujący sposób: zmodyfikuj plik Employee.pm.

#!/usr/bin/perl

package Employee;
use Person;
use strict;
our @ISA = qw(Person);    # inherits from Person

# Override constructor
sub new {
   my ($class) = @_;

   # Call the constructor of the parent class, Person.
   my $self = $class->SUPER::new( $_[1], $_[2], $_[3] );
   # Add few more attributes
   $self->{_id}   = undef;
   $self->{_title} = undef;
   bless $self, $class;
   return $self;
}

# Override helper function
sub getFirstName {
   my( $self ) = @_;
   # This is child class function.
   print "This is child class helper function\n";
   return $self->{_firstName};
}

# Add more methods
sub setLastName{
   my ( $self, $lastName ) = @_;
   $self->{_lastName} = $lastName if defined($lastName);
   return $self->{_lastName};
}

sub getLastName {
   my( $self ) = @_;
   return $self->{_lastName};
}

1;

Spróbujmy teraz ponownie użyć obiektu Employee w naszym pliku main.pl i go wykonać.

#!/usr/bin/perl

use Employee;

$object = new Employee( "Mohammad", "Saleem", 23234345);
# Get first name which is set using constructor.
$firstName = $object->getFirstName();

print "Before Setting First Name is : $firstName\n";

# Now Set first name using helper function.
$object->setFirstName( "Mohd." );

# Now get first name set by helper function.
$firstName = $object->getFirstName();
print "After Setting First Name is : $firstName\n";

Kiedy wykonujemy powyższy program, daje on następujący wynik -

First Name is Mohammad
Last Name is Saleem
SSN is 23234345
This is child class helper function
Before Setting First Name is : Mohammad
This is child class helper function
After Setting First Name is : Mohd.

Domyślne automatyczne ładowanie

Perl oferuje funkcję, której nie znajdziesz w żadnym innym języku programowania: domyślny podprogram. Co oznacza, że ​​jeśli zdefiniujesz funkcję o nazwieAUTOLOAD(),wtedy każde wywołanie niezdefiniowanych podprogramów automatycznie wywoła funkcję AUTOLOAD (). Nazwa brakującego podprogramu jest dostępna w tym podprogramie jako $ AUTOLOAD.

Domyślna funkcja automatycznego ładowania jest bardzo przydatna do obsługi błędów. Oto przykład implementacji AUTOLOAD, możesz zaimplementować tę funkcję na swój własny sposób.

sub AUTOLOAD {
   my $self = shift;
   my $type = ref ($self) || croak "$self is not an object";
   my $field = $AUTOLOAD;
   $field =~ s/.*://;
   unless (exists $self->{$field}) {
      croak "$field does not exist in object/class $type";
   }
   if (@_) {
      return $self->($name) = shift;
   } else {
      return $self->($name);
   }
}

Destruktory i odśmiecanie

Jeśli wcześniej programowałeś za pomocą programowania obiektowego, będziesz świadomy potrzeby utworzenia pliku destructoraby zwolnić pamięć przydzieloną obiektowi po zakończeniu korzystania z niego. Perl robi to automatycznie, gdy tylko obiekt znajdzie się poza zasięgiem.

W przypadku, gdy chcesz zaimplementować swój destruktor, który powinien zająć się zamykaniem plików lub wykonywaniem dodatkowego przetwarzania, musisz zdefiniować specjalną metodę o nazwie DESTROY. Ta metoda zostanie wywołana na obiekcie tuż przed zwolnieniem przez Perl przydzielonej mu pamięci. Pod wszystkimi innymi względami metoda DESTROY jest taka sama, jak każda inna metoda i możesz zaimplementować dowolną logikę w tej metodzie.

Metoda destruktora to po prostu funkcja składowa (podprocedura) o nazwie DESTROY, która zostanie wywołana automatycznie w następujących przypadkach:

  • Gdy zmienna odwołania do obiektu wykracza poza zakres.
  • Gdy zmienna odniesienia do obiektu jest niezdefiniowana.
  • Kiedy skrypt się kończy
  • Kiedy interpreter perla kończy działanie

Na przykład możesz po prostu umieścić następującą metodę DESTROY w swojej klasie -

package MyClass;
...
sub DESTROY {
   print "MyClass::DESTROY called\n";
}

Przykład języka Perl zorientowany obiektowo

Oto kolejny ładny przykład, który pomoże ci zrozumieć koncepcje zorientowane obiektowo w Perlu. Umieść ten kod źródłowy w dowolnym pliku Perla i wykonaj go.

#!/usr/bin/perl

# Following is the implementation of simple Class.
package MyClass;

sub new {
   print "MyClass::new called\n";
   my $type = shift;            # The package/type name
   my $self = {};               # Reference to empty hash
   return bless $self, $type;   
}

sub DESTROY {
   print "MyClass::DESTROY called\n";
}

sub MyMethod {
   print "MyClass::MyMethod called!\n";
}


# Following is the implemnetation of Inheritance.
package MySubClass;

@ISA = qw( MyClass );

sub new {
   print "MySubClass::new called\n";
   my $type = shift;            # The package/type name
   my $self = MyClass->new;     # Reference to empty hash
   return bless $self, $type;  
}

sub DESTROY {
   print "MySubClass::DESTROY called\n";
}

sub MyMethod {
   my $self = shift;
   $self->SUPER::MyMethod();
   print "   MySubClass::MyMethod called!\n";
}

# Here is the main program using above classes.
package main;

print "Invoke MyClass method\n";

$myObject = MyClass->new();
$myObject->MyMethod();

print "Invoke MySubClass method\n";

$myObject2 = MySubClass->new();
$myObject2->MyMethod();

print "Create a scoped object\n";
{
   my $myObject2 = MyClass->new();
}
# Destructor is called automatically here

print "Create and undef an object\n";
$myObject3 = MyClass->new();
undef $myObject3;

print "Fall off the end of the script...\n";
# Remaining destructors are called automatically here

Kiedy wykonujemy powyższy program, daje on następujący wynik -

Invoke MyClass method
MyClass::new called
MyClass::MyMethod called!
Invoke MySubClass method
MySubClass::new called
MyClass::new called
MyClass::MyMethod called!
MySubClass::MyMethod called!
Create a scoped object
MyClass::new called
MyClass::DESTROY called
Create and undef an object
MyClass::new called
MyClass::DESTROY called
Fall off the end of the script...
MyClass::DESTROY called
MySubClass::DESTROY called