Programmazione orientata agli oggetti in PERL

Abbiamo già studiato i riferimenti in array e hash anonimi Perl e Perl. Il concetto di Object Oriented in Perl è molto basato su riferimenti, array e hash anonimi. Cominciamo ad apprendere i concetti di base del Perl orientato agli oggetti.

Nozioni di base sugli oggetti

Ci sono tre termini principali, spiegati dal punto di vista di come Perl gestisce gli oggetti. I termini sono oggetto, classe e metodo.

  • Un objectall'interno di Perl è semplicemente un riferimento a un tipo di dati che sa a quale classe appartiene. L'oggetto viene memorizzato come riferimento in una variabile scalare. Poiché uno scalare contiene solo un riferimento all'oggetto, lo stesso scalare può contenere oggetti diversi in classi diverse.

  • UN class all'interno di Perl c'è un pacchetto che contiene i metodi corrispondenti richiesti per creare e manipolare oggetti.

  • UN methodall'interno di Perl c'è una subroutine, definita con il pacchetto. Il primo argomento del metodo è un riferimento a un oggetto o un nome di pacchetto, a seconda che il metodo influenzi l'oggetto corrente o la classe.

Perl fornisce un file bless() funzione, che viene utilizzata per restituire un riferimento che alla fine diventa un oggetto.

Definizione di una classe

È molto semplice definire una classe in Perl. Una classe corrisponde a un pacchetto Perl nella sua forma più semplice. Per creare una classe in Perl, prima costruiamo un pacchetto.

Un pacchetto è un'unità autonoma di variabili e subroutine definite dall'utente, che possono essere riutilizzate più e più volte.

I pacchetti Perl forniscono uno spazio dei nomi separato all'interno di un programma Perl che mantiene le subroutine e le variabili indipendenti dal conflitto con quelle di altri pacchetti.

Per dichiarare una classe denominata Persona in Perl facciamo:

package Person;

L'ambito della definizione del pacchetto si estende alla fine del file o fino a quando non viene rilevata un'altra parola chiave del pacchetto.

Creazione e utilizzo di oggetti

Per creare un'istanza di una classe (un oggetto) abbiamo bisogno di un costruttore di oggetti. Questo costruttore è un metodo definito all'interno del pacchetto. La maggior parte dei programmatori sceglie di chiamare nuovo questo metodo di costruzione di oggetti, ma in Perl puoi usare qualsiasi nome.

Puoi usare qualsiasi tipo di variabile Perl come oggetto in Perl. La maggior parte dei programmatori Perl sceglie i riferimenti agli array o agli hash.

Creiamo il nostro costruttore per la nostra classe Person usando un riferimento hash Perl. Quando si crea un oggetto, è necessario fornire un costruttore, che è una subroutine all'interno di un pacchetto che restituisce un riferimento all'oggetto. Il riferimento all'oggetto viene creato benedendo un riferimento alla classe del pacchetto. Ad esempio:

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;
}

Vediamo ora come creare un oggetto.

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

Puoi usare hash semplice nel tuo consturctor se non vuoi assegnare alcun valore a nessuna variabile di classe. Ad esempio:

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

Definizione di metodi

Altri linguaggi orientati agli oggetti hanno il concetto di sicurezza dei dati per impedire a un programmatore di modificare direttamente i dati di un oggetto e forniscono metodi di accesso per modificare i dati dell'oggetto. Perl non ha variabili private ma possiamo ancora usare il concetto di metodi di supporto per manipolare i dati degli oggetti.

Definiamo un metodo di supporto per ottenere il nome di una persona -

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

Un'altra funzione di supporto per impostare il nome di una persona -

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

Ora diamo uno sguardo all'esempio completo: Mantieni il pacchetto Person e le funzioni di supporto nel file 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;

Ora utilizziamo l'oggetto Person nel file dipendente.pl come segue:

#!/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";

Quando eseguiamo il programma sopra, produce il seguente risultato:

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

Eredità

La programmazione orientata agli oggetti ha un concetto molto buono e utile chiamato ereditarietà. Ereditarietà significa semplicemente che le proprietà e i metodi di una classe genitore saranno disponibili per le classi figlie. Quindi non devi scrivere lo stesso codice ancora e ancora, puoi semplicemente ereditare una classe genitore.

Ad esempio, possiamo avere una classe Employee, che eredita da Person. Questa viene definita relazione "isa" perché un dipendente è una persona. Perl ha una variabile speciale, @ISA, per aiutare con questo. @ISA governa l'ereditarietà (metodo).

Di seguito sono riportati i punti importanti da considerare durante l'utilizzo dell'ereditarietà:

  • Perl ricerca la classe dell'oggetto specificato per il metodo o l'attributo dato, cioè la variabile.

  • Perl ricerca le classi definite nell'array @ISA della classe di oggetti.

  • Se non viene trovato alcun metodo nei passaggi 1 o 2, Perl usa una subroutine AUTOLOAD, se ne trova una nell'albero @ISA.

  • Se non è ancora possibile trovare un metodo corrispondente, Perl cerca il metodo all'interno della classe UNIVERSAL (pacchetto) che fa parte della libreria Perl standard.

  • Se il metodo non è stato ancora trovato, Perl si arrende e solleva un'eccezione di runtime.

Quindi, per creare una nuova classe Employee che erediterà metodi e attributi dalla nostra classe Person, codifichiamo semplicemente come segue: Mantieni questo codice in Employee.pm.

#!/usr/bin/perl

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

Ora Employee Class ha tutti i metodi e gli attributi ereditati dalla classe Person e puoi usarli come segue: Usa il file main.pl per testarlo -

#!/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";

Quando eseguiamo il programma sopra, produce il seguente risultato:

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

Sostituzione del metodo

La classe figlia Employee eredita tutti i metodi dalla classe genitore Person. Ma se desideri sovrascrivere questi metodi nella tua classe figlia, puoi farlo fornendo la tua implementazione. Puoi aggiungere le tue funzioni aggiuntive nella classe figlia oppure puoi aggiungere o modificare la funzionalità di un metodo esistente nella sua classe genitore. Può essere fatto come segue: modificare il file 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;

Ora proviamo di nuovo a utilizzare l'oggetto Employee nel nostro file main.pl ed eseguiamolo.

#!/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";

Quando eseguiamo il programma sopra, produce il seguente risultato:

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.

Caricamento automatico predefinito

Perl offre una funzionalità che non troveresti in nessun altro linguaggio di programmazione: una subroutine predefinita. Il che significa che, se definisci una funzione chiamataAUTOLOAD(),quindi qualsiasi chiamata a subroutine non definite chiamerà automaticamente la funzione AUTOLOAD (). Il nome della subroutine mancante è accessibile all'interno di questa subroutine come $ AUTOLOAD.

La funzionalità di caricamento automatico predefinita è molto utile per la gestione degli errori. Ecco un esempio per implementare AUTOLOAD, puoi implementare questa funzione a modo tuo.

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);
   }
}

Distruttori e Garbage Collection

Se in precedenza hai programmato utilizzando la programmazione orientata agli oggetti, sarai consapevole della necessità di creare un file destructorper liberare la memoria allocata all'oggetto al termine dell'utilizzo. Perl lo fa automaticamente non appena l'oggetto esce dall'ambito.

Nel caso in cui desideri implementare il tuo distruttore, che dovrebbe occuparsi di chiudere i file o eseguire un'elaborazione extra, devi definire un metodo speciale chiamato DESTROY. Questo metodo verrà chiamato sull'oggetto appena prima che Perl liberi la memoria assegnata all'oggetto. Sotto tutti gli altri aspetti, il metodo DESTROY è proprio come qualsiasi altro metodo e puoi implementare qualsiasi logica tu voglia all'interno di questo metodo.

Un metodo distruttore è semplicemente una funzione membro (subroutine) denominata DESTROY, che verrà chiamata automaticamente nei seguenti casi:

  • Quando la variabile del riferimento all'oggetto esce dall'ambito.
  • Quando la variabile del riferimento all'oggetto è indefinita.
  • Quando lo script termina
  • Quando termina l'interprete perl

Ad esempio, puoi semplicemente inserire il seguente metodo DESTROY nella tua classe:

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

Esempio di Perl orientato agli oggetti

Ecco un altro bell'esempio, che ti aiuterà a comprendere i concetti orientati agli oggetti di Perl. Metti questo codice sorgente in qualsiasi file perl ed eseguilo.

#!/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

Quando eseguiamo il programma sopra, produce il seguente risultato:

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