Programmation orientée objet Perl

Il existe deux implémentations différentes de la programmation orientée objet en Perl :

  • L'une est basée sur des tables de hachage anonymes, où l'essence de chaque instance d'objet est une référence à une table de hachage anonyme. Dans cette table de hachage anonyme, tous les attributs d'instance sont stockés.

  • L'autre est basée sur des tableaux. Lors de la définition d'une classe, nous créons un tableau pour chaque attribut d'instance, et l'essence de chaque instance d'objet est une référence à un indice d'une ligne dans ces tableaux. Dans ces tableaux, tous les attributs d'instance sont stockés.


Concepts de base de la programmation orientée objet

La programmation orientée objet comporte de nombreux concepts de base. Nous en abordons ici trois : les objets, les classes et les méthodes.

  • ObjetUn objet est une référence à un élément de données dans une classe.

  • ClasseUne classe est un package Perl qui contient les méthodes fournies pour l'objet.

  • MéthodeUne méthode est une sous-routine Perl dont le premier paramètre est le nom de la classe.

Perl fournit la fonction bless(), qui est utilisée pour construire des objets. En associant une référence au nom de la classe via bless, le retour de cette référence construit un objet.


Définition de classe

Une classe n'est qu'un simple package.

Vous pouvez utiliser un package comme une classe et utiliser les fonctions du package comme méthodes de la classe.

Les packages Perl fournissent des espaces de noms indépendants, de sorte que les méthodes et les noms de variables de différents packages n'entrent pas en conflit.

Les fichiers de classe Perl ont l'extension .pm.

Ensuite, nous créons une classe Person :

package Person;

La portée du code d'une classe s'étend jusqu'à la dernière ligne du fichier de script, ou jusqu'au prochain mot-clé "package".


Création et utilisation d'objets

Pour créer une instance (objet) d'une classe, nous devons définir un constructeur. La plupart des programmes utilisent le nom de la classe comme constructeur, mais en Perl, vous pouvez utiliser n'importe quel nom.

Vous pouvez utiliser diverses variables Perl comme objets Perl. Dans la plupart des cas, nous utilisons des références à des tableaux ou à des hachages.

Ensuite, nous créons un constructeur pour la classe Person, en utilisant une référence de hachage Perl.

Lors de la création d'un objet, vous devez fournir un constructeur, qui est une sous-routine renvoyant une référence à l'objet.

L'exemple est le suivant :

Exemple

package Person; sub new { my $class = shift; my $self = { _firstName => shift, _lastName => shift, _ssn => shift, }; # Afficher les informations de l'utilisateur print "Nom :$self->{_firstName}\n"; print "Nom de famille :$self->{_lastName}\n"; print "Numéro :$self->{_ssn}\n"; bless $self, $class; return $self; }

Ensuite, nous créons un objet :

$object = new Person( "小明", "王", 23234345);

Définition des méthodes

Les méthodes de classe Perl ne sont que des sous-programmes Perl, c'est-à-dire ce que l'on appelle communément des fonctions membres.

Dans la POO Perl, la définition d'une méthode ne fournit aucune syntaxe spéciale, mais elle exige que le premier paramètre d'une méthode soit l'objet ou le package à partir duquel elle est référencée.

Perl ne fournit pas de variables privées, mais nous pouvons gérer les données d'objet via des méthodes auxiliaires.

Ensuite, nous définissons une méthode pour obtenir le nom :

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

Cela peut aussi s'écrire comme ceci :

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

Ensuite, nous modifions le code dans le fichier Person.pm comme suit :

Exemple

#!/usr/bin/perl package Person; sub new { my $class = shift; my $self = { _firstName => shift, _lastName => shift, _ssn => shift, }; # Afficher les informations de l'utilisateur print "Nom :$self->{_firstName}\n"; print "Nom de famille :$self->{_lastName}\n"; print "Numéro :$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;

Le code du script employee.pl est le suivant :

Exemple

#!/usr/bin/perl use Person; $object = new Person( "Xiaoming", "Wang", 23234345); # Obtenir le nom $firstName = $object->getFirstName(); print "Le nom avant la définition est :$firstName\n"; # Utiliser la fonction d'assistance pour définir le nom $object->setFirstName( "Xiaoqiang" ); # Obtenir le nom via la fonction d'assistance $firstName = $object->getFirstName(); print "Le nom après la définition est :$firstName\n";

Après l'exécution du programme ci-dessus, la sortie est :

$ perl employee.pl
名字:小明
姓氏:王
编号:23234345
设置前姓名为 : 小明
设置后姓名为 : 小强

Héritage

En Perl, les méthodes de classe sont héritées via le tableau @ISA, qui contient les noms d'autres paquetages (classes). L'héritage des variables doit être défini explicitement.

L'héritage multiple se produit lorsque ce tableau @ISA contient plusieurs noms de classes (paquetages).

Via @ISA, seules les méthodes peuvent être héritées ; les données ne peuvent pas être héritées.

Ensuite, nous créons une classe Employee qui hérite de la classe Person.

Le code du fichier Employee.pm est le suivant :

Exemple

#!/usr/bin/perl package Employee; use Person; use strict; our @ISA = qw(Person); # Hériter de Person

Maintenant, la classe Employee contient toutes les méthodes et attributs de la classe Person. Nous saisissons le code suivant dans le fichier main.pl et l'exécutons :

Exemple

#!/usr/bin/perl use Employee; $object = new Employee( "Xiaoming", "Wang", 23234345); # Obtenir le nom $firstName = $object->getFirstName(); print "Le nom avant la définition est :$firstName\n"; # Utiliser la fonction d'assistance pour définir le nom $object->setFirstName( "Xiaoqiang" ); # Obtenir le nom via la fonction d'assistance $firstName = $object->getFirstName(); print "Le nom après la définition est :$firstName\n";

Après l'exécution du programme ci-dessus, la sortie est :

$ perl main.pl
名字:小明
姓氏:王
编号:23234345
设置前姓名为 : 小明
设置后姓名为 : 小强

Redéfinition de méthode

Dans l'exemple ci-dessus, la classe Employee hérite de la classe Person. Toutefois, si les méthodes de la classe Person ne peuvent pas répondre aux exigences, elles doivent être redéfinies.

Ensuite, nous ajoutons quelques nouvelles méthodes à la classe Employee et redéfinissons des méthodes de la classe Person :

Exemple

#!/usr/bin/perl package Employee; use Person; use strict; our @ISA = qw(Person); # Hériter de Person # Redéfinir le constructeur sub new { my ($class) = @_; # Appeler le constructeur de la classe parente my $self = $class->SUPER::new( $_[1], $_[2], $_[3] ); # Ajouter d'autres attributs $self->{_id} = undef; $self->{_title} = undef; bless $self, $class; return $self; } # Redéfinir la méthode sub getFirstName { my( $self ) = @_; # Ceci est une fonction de sous-classe print "Ceci est une fonction de sous-classe\n"; return $self->{_firstName}; } # Ajouter une méthode sub setLastName{ my ( $self, $lastName ) = @_; $self->{_lastName} = $lastName if defined($lastName); return $self->{_lastName}; } sub getLastName { my( $self ) = @_; return $self->{_lastName}; } 1;

Nous saisissons le code suivant dans le fichier main.pl et l'exécutons :

Exemple

#!/usr/bin/perl use Employee; $object = new Employee( "Xiaoming", "Wang", 23234345); # Obtenir le nom, en utilisant le constructeur modifié $firstName = $object->getFirstName(); print "Le nom avant la définition est :$firstName\n"; # Utiliser la fonction d'assistance pour définir le nom $object->setFirstName( "Xiaoqiang" ); # Obtenir le nom via la fonction d'assistance $firstName = $object->getFirstName(); print "Le nom après la définition est :$firstName\n";

Après l'exécution du programme ci-dessus, la sortie est :

$ perl main.pl
名字:小明
姓氏:王
编号:23234345
这是子类函数
设置前姓名为 : 小明
这是子类函数
设置后姓名为 : 小强

Chargement automatique

Si la méthode demandée est introuvable dans la classe actuelle, toutes les classes de base de la classe actuelle, ou la classe UNIVERSAL, Perl cherche alors une méthode nommée AUTOLOAD(). Si AUTOLOAD est trouvée, elle est appelée, et la variable globale $AUTOLOAD est définie au nom pleinement qualifié de la méthode manquante.

Si cela échoue encore, Perl déclare une erreur et échoue.

Si vous ne voulez pas hériter d'AUTOLOAD de la classe de base, c'est simple : une seule ligne :

sub AUTOLOAD;

Destructeurs et ramasse-miettes

Lorsque la dernière référence à un objet est libérée, l'objet est automatiquement détruit.

Si vous voulez faire quelque chose pendant la destruction, vous pouvez définir une méthode nommée "DESTROY" dans la classe. Elle est automatiquement appelée au moment approprié et effectue des actions de nettoyage supplémentaires comme vous les définissez.

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

Perl passe la référence de l'objet comme unique paramètre à DESTROY. Notez que cette référence est en lecture seule, ce qui signifie que vous ne pouvez pas la modifier en accédant à $_

Si vous re-bénissez la référence de l'objet avant que le destructeur ne retourne, Perl appellera alors la méthode DESTROY de l'objet que vous avez re-béni après le retour du destructeur. Cela vous donne l'occasion d'appeler le destructeur de la classe de base ou d'une autre classe que vous spécifiez. Il convient de noter que DESTROY peut également être appelé manuellement, mais c'est généralement inutile.

Après la libération de l'objet courant, les autres objets contenus dans l'objet courant sont automatiquement libérés.


Exemple orienté objet en Perl

Nous pouvons mieux comprendre l'application de la POO en Perl à travers l'exemple suivant :

Exemple

#!/usr/bin/perl # Ce qui suit est une simple implémentation de classe package MyClass; sub new { print "MyClass::new called\n"; my $type = shift; # Nom du package my $self = {}; # Référence à un hachage vide return bless $self, $type; } sub DESTROY { print "MyClass::DESTROY called\n"; } sub MyMethod { print "MyClass::MyMethod called!\n"; } # Implémentation de l'héritage package MySubClass; @ISA = qw( MyClass ); sub new { print "MySubClass::new appelé\n"; my $type = shift; # Nom du paquet my $self = MyClass->new; # Référence à un hachage vide return bless $self, $type; } sub DESTROY { print "MySubClass::DESTROY appelé\n"; } sub MyMethod { my $self = shift; $self->SUPER::MyMethod(); print " MySubClass::MyMethod appelé !\n"; } # Programme principal appelant les classes ci-dessus package main; print "Appel de la méthode MyClass\n"; $myObject = MyClass->new(); $myObject->MyMethod(); print "Appel de la méthode MySubClass\n"; $myObject2 = MySubClass->new(); $myObject2->MyMethod(); print "Création d'un objet à portée limitée\n"; { my $myObject2 = MyClass->new(); } # Appeler automatiquement le destructeur print "Créer un objet\n"; $myObject3 = MyClass->new(); undef $myObject3; print "L'exécution du script est terminée...\n"; # Exécution automatique du destructeur

En exécutant le programme ci-dessus, la sortie est :

调用 MyClass 方法
MyClass::new called
MyClass::MyMethod called!
调用 MySubClass 方法
MySubClass::new called
MyClass::new called
MyClass::MyMethod called!
   MySubClass::MyMethod called!
创建一个作用域对象
MyClass::new called
MyClass::DESTROY called
创建对象
MyClass::new called
MyClass::DESTROY called
脚本执行结束...
MyClass::DESTROY called
MySubClass::DESTROY called
Autres extensions