Perl orienté objet


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. L'essence de chaque instance d'objet est un pointeur Une référence. à la table de hachage anonyme. Dans cette table de hachage anonyme, tous les attributs d'instance sont stockés.

  • La seconde est basée sur des tableaux. Lors de la définition d'une classe, nous créerons un tableau pour chaque attribut d'instance, et l'essence de chaque instance d'objet est un pointeur vers ces tableaux. à un index de ligne. Dans ces tableaux, toutes les propriétés d'instance sont stockées.


Concepts de base de l'orientation objet

Il existe de nombreux concepts de base de l'orientation objet, nous en acceptons ici trois : les objets, les classes et les méthodes.

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

  • Class : Une classe est un package Perl qui contient des classes qui fournissent des méthodes objet.

  • Méthode : La méthode est un sous-programme Perl et le nom de la classe est son premier paramètre.

Perl fournit la fonction bless(). bless est utilisée pour construire des objets. Bless associe une référence au nom de la classe et renvoie la référence pour construire un objet.


Définition de classe

Une classe n'est qu'un simple package.

Vous pouvez utiliser un package comme 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 dans différents packages n'entreront pas en conflit.

L'extension du fichier de classe Perl est .pm.

Ensuite, nous créons une classe Person :

package Person;

La plage de codes de la classe atteint la dernière ligne du fichier de script, ou avant le mot-clé suivant du 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, n'importe quel nom peut être utilisé en Perl .

Vous pouvez utiliser diverses variables Perl comme objets Perl. La plupart du temps, nous utiliserons des tableaux ou des hachages de référence.

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

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

L'exemple est le suivant :

package Person;
sub new
{
    my $class = shift;
    my $self = {
        _firstName => shift,
        _lastName  => shift,
        _ssn       => shift,
    };
    # 输出用户信息
    print "名字:$self->{_firstName}\n";
    print "姓氏:$self->{_lastName}\n";
    print "编号:$self->{_ssn}\n";
    bless $self, $class;
    return $self;
}

Ensuite nous créons un objet :

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

Définir la méthode

La méthode de la classe Perl n'est qu'un enfant de Perl. C'est juste un programme, également appelé fonction membre.

La définition de méthode Perl en Perl orienté objet ne fournit aucune syntaxe particulière, mais stipule que le premier paramètre de la méthode est l'objet ou le package auquel il est référencé.

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

Il 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 du fichier Person.pm, Comme indiqué ci-dessous:

#!/usr/bin/perl 

package Person;

sub new
{
    my $class = shift;
    my $self = {
        _firstName => shift,
        _lastName  => shift,
        _ssn       => shift,
    };
    # 输出用户信息
    print "名字:$self->{_firstName}\n";
    print "姓氏:$self->{_lastName}\n";
    print "编号:$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;

employee.pl Le code du script est le suivant :

#!/usr/bin/perl

use Person;

$object = new Person( "小明", "王", 23234345);
# 获取姓名
$firstName = $object->getFirstName();

print "设置前姓名为 : $firstName\n";

# 使用辅助函数设置姓名
$object->setFirstName( "小强" );

# 通过辅助函数获取姓名
$firstName = $object->getFirstName();
print "设置后姓名为 : $firstName\n";

Après l'exécution du programme ci-dessus, le résultat de sortie est :

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

Inherit

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

L'héritage multiple signifie que le tableau @ISA contient plusieurs noms de classe (package).

Seules les méthodes peuvent être héritées via @ISA, pas les données.

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

Le code du fichier Employee.pm est le suivant :

#!/usr/bin/perl

package Employee;
use Person;
use strict;
our @ISA = qw(Person);    # 从 Person 继承

Maintenant la classe Employee contient toutes les méthodes et propriétés de la classe Person On rentre le code suivant dans le main.pl. fichier et exécutez-le :

#!/usr/bin/perl

use Employee;

$object = new Employee( "小明", "王", 23234345);
# 获取姓名
$firstName = $object->getFirstName();

print "设置前姓名为 : $firstName\n";

# 使用辅助函数设置姓名
$object->setFirstName( "小强" );

# 通过辅助函数获取姓名
$firstName = $object->getFirstName();
print "设置后姓名为 : $firstName\n";

Après l'exécution du programme ci-dessus, le résultat de sortie est :

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

Réécriture de méthode

Dans l'exemple ci-dessus, la classe Employee hérite la classe Person, mais si la classe Person Si la méthode ne peut pas répondre aux besoins, la méthode doit être réécrite.

Ensuite, nous ajoutons de nouvelles méthodes à la classe Employee et remplaçons les méthodes de la classe Person :

#!/usr/bin/perl

package Employee;
use Person;
use strict;
our @ISA = qw(Person);    # 从 Person 继承

# 重写构造函数
sub new {
    my ($class) = @_;

    # 调用父类的构造函数
    my $self = $class->SUPER::new( $_[1], $_[2], $_[3] );
    # 添加更多属性
    $self->{_id}   = undef;
    $self->{_title} = undef;
    bless $self, $class;
    return $self;
}

# 重写方法
sub getFirstName {
    my( $self ) = @_;
    # 这是子类函数
    print "这是子类函数\n";
    return $self->{_firstName};
}

# 添加方法
sub setLastName{
    my ( $self, $lastName ) = @_;
    $self->{_lastName} = $lastName if defined($lastName);
    return $self->{_lastName};
}

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

1;

Nous entrons le code suivant dans le fichier main.pl et exécutons :

#!/usr/bin/perl

use Employee;

$object = new Employee( "小明", "王", 23234345);
# 获取姓名,使用修改后的构造函数
$firstName = $object->getFirstName();

print "设置前姓名为 : $firstName\n";

# 使用辅助函数设置姓名
$object->setFirstName( "小强" );

# 通过辅助函数获取姓名
$firstName = $object->getFirstName();
print "设置后姓名为 : $firstName\n";

Après avoir exécuté le programme ci-dessus, le résultat de sortie est :

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

Chargé par défaut

S'il se trouve dans la classe actuelle, toutes les classes de base de la classe actuelle, et la classe UNIVERSELLE, je ne trouve pas de moyen de la demander. A ce moment, une méthode nommée AUTOLOAD() est à nouveau recherchée. Si AUTOLOAD est trouvé, alors Appelez et définissez la variable globale $AUTOLOAD sur le nom complet de la méthode manquante.

Si cela ne fonctionne pas, Perl échoue avec une erreur.

Si vous ne souhaitez pas hériter d'AUTOLOAD de la classe de base, c'est très simple, juste une phrase :

sub AUTOLOAD;

Destructeur et garbage collection

Quand le dernière référence de l'objet Une fois relâché, l'objet est automatiquement détruit.

Si vous souhaitez faire quelque chose pendant la destruction, alors vous pouvez définir une méthode nommée "DESTROY" dans la classe. Il sera automatiquement appelé au moment opportun et effectuera des actions de nettoyage supplémentaires à votre guise.

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

Perl traite les références d'objet comme Le seul argument passé est DESTROY. Notez que cette référence est en lecture seule, ce qui signifie que vous ne pouvez pas la modifier en accédant à $_[0]. (Note du traducteur : voir perlsub) Mais l'objet lui-même (tel que "${$_[0]" Ou "@{$_[0]}" et "%{$_[0]}" etc.) sont toujours accessibles en écriture.

Si vous bénissez à nouveau la référence d'objet avant le retour du destructeur, Perl appellera alors la méthode DESTROY de l'objet que vous avez béni à nouveau après le retour du destructeur. Cela vous donne la possibilité d'appeler le destructeur de la classe de base ou d'autres classes que vous spécifiez. Il convient de noter que DESTROY peut également être appelé manuellement, mais ce n'est généralement pas nécessaire.

Une fois l'objet actuel libéré, les autres objets contenus dans l'objet actuel seront automatiquement libérés.


Exemples orientés objet Perl

Nous pouvons mieux comprendre l'application orientée objet de Perl à travers les exemples suivants :

#!/usr/bin/perl

# 下面是简单的类实现
package MyClass;

sub new
{
   print "MyClass::new called\n";
   my $type = shift;            # 包名
   my $self = {};               # 引用空哈希
   return bless $self, $type;   
}

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

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


# 继承实现
package MySubClass;

@ISA = qw( MyClass );

sub new
{
   print "MySubClass::new called\n";
   my $type = shift;            # 包名
   my $self = MyClass->new;     # 引用空哈希
   return bless $self, $type;  
}

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

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

# 调用以上类的主程序
package main;

print "调用 MyClass 方法\n";

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

print "调用 MySubClass 方法\n";

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

print "创建一个作用域对象\n";
{
  my $myObject2 = MyClass->new();
}
# 自动调用析构函数

print "创建对象\n";
$myObject3 = MyClass->new();
undef $myObject3;

print "脚本执行结束...\n";
# 自动执行析构函数

Exécutez le programme ci-dessus, le résultat le résultat 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