Programação Orientada a Objetos em PERL

Já estudamos referências em matrizes e hashes anônimos Perl e Perl. O conceito de Orientação a Objetos em Perl é muito baseado em referências e array anônimo e hashes. Vamos começar a aprender os conceitos básicos de Perl Orientado a Objetos.

Noções básicas de objeto

Existem três termos principais, explicados do ponto de vista de como o Perl trata os objetos. Os termos são objeto, classe e método.

  • A objectem Perl é apenas uma referência a um tipo de dados que sabe a que classe pertence. O objeto é armazenado como referência em uma variável escalar. Como um escalar contém apenas uma referência ao objeto, o mesmo escalar pode conter objetos diferentes em classes diferentes.

  • UMA class dentro do Perl está um pacote que contém os métodos correspondentes necessários para criar e manipular objetos.

  • UMA methoddentro do Perl é uma sub-rotina, definida com o pacote. O primeiro argumento para o método é uma referência de objeto ou um nome de pacote, dependendo se o método afeta o objeto atual ou a classe.

Perl fornece um bless() função, que é usada para retornar uma referência que finalmente se torna um objeto.

Definindo uma Classe

É muito simples definir uma classe em Perl. Uma classe corresponde a um pacote Perl em sua forma mais simples. Para criar uma classe em Perl, primeiro construímos um pacote.

Um pacote é uma unidade autocontida de variáveis ​​e sub-rotinas definidas pelo usuário, que pode ser reutilizada continuamente.

Pacotes Perl fornecem um namespace separado dentro de um programa Perl que mantém sub-rotinas e variáveis ​​independentes do conflito com aquelas em outros pacotes.

Para declarar uma classe chamada Person em Perl, fazemos -

package Person;

O escopo da definição do pacote se estende até o final do arquivo ou até que outra palavra-chave do pacote seja encontrada.

Criando e usando objetos

Para criar uma instância de uma classe (um objeto), precisamos de um construtor de objeto. Este construtor é um método definido no pacote. A maioria dos programadores escolhe nomear este método de construtor de objeto como novo, mas em Perl você pode usar qualquer nome.

Você pode usar qualquer tipo de variável Perl como um objeto em Perl. A maioria dos programadores Perl escolhe referências a arrays ou hashes.

Vamos criar nosso construtor para nossa classe Person usando uma referência de hash Perl. Ao criar um objeto, você precisa fornecer um construtor, que é uma sub-rotina dentro de um pacote que retorna uma referência de objeto. A referência do objeto é criada abençoando uma referência à classe do pacote. Por exemplo -

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

Agora vamos ver como criar um objeto.

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

Você pode usar hash simples em seu construtor se não quiser atribuir nenhum valor a nenhuma variável de classe. Por exemplo -

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

Definindo Métodos

Outras linguagens orientadas a objetos têm o conceito de segurança de dados para evitar que um programador altere os dados de um objeto diretamente e fornecem métodos de acesso para modificar os dados do objeto. Perl não tem variáveis ​​privadas, mas ainda podemos usar o conceito de métodos auxiliares para manipular os dados do objeto.

Vamos definir um método auxiliar para obter o primeiro nome da pessoa -

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

Outra função auxiliar para definir o primeiro nome da pessoa -

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

Agora vamos dar uma olhada em um exemplo completo: Mantenha o pacote Person e as funções auxiliares no arquivo 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;

Agora vamos fazer uso do objeto Person no arquivo employee.pl da seguinte maneira -

#!/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 executamos o programa acima, ele produz o seguinte resultado -

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

Herança

A programação orientada a objetos tem um conceito muito bom e útil chamado herança. Herança significa simplesmente que as propriedades e métodos de uma classe pai estarão disponíveis para as classes filho. Assim, você não precisa escrever o mesmo código repetidamente, você pode simplesmente herdar uma classe pai.

Por exemplo, podemos ter uma classe Employee, que herda de Person. Isso é conhecido como relacionamento "isa" porque um funcionário é uma pessoa. Perl tem uma variável especial, @ISA, para ajudar com isso. @ISA governa a herança (método).

A seguir estão os pontos importantes a serem considerados ao usar a herança -

  • Perl pesquisa a classe do objeto especificado para o método ou atributo fornecido, ou seja, variável.

  • Perl pesquisa as classes definidas na matriz @ISA da classe de objeto.

  • Se nenhum método for encontrado nas etapas 1 ou 2, o Perl usa uma sub-rotina AUTOLOAD, se houver uma na árvore @ISA.

  • Se um método compatível ainda não puder ser encontrado, então o Perl procura o método dentro da classe UNIVERSAL (pacote) que vem como parte da biblioteca Perl padrão.

  • Se o método ainda não foi encontrado, o Perl desiste e levanta uma exceção de tempo de execução.

Portanto, para criar uma nova classe Employee que herdará métodos e atributos de nossa classe Person, simplesmente codificamos da seguinte maneira: Mantenha este código em Employee.pm.

#!/usr/bin/perl

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

Agora, a classe Employee tem todos os métodos e atributos herdados da classe Person e você pode usá-los da seguinte maneira: Use o arquivo main.pl para testá-lo -

#!/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 executamos o programa acima, ele produz o seguinte resultado -

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

Substituição de método

A classe filha Employee herda todos os métodos da classe pai Person. Mas se você quiser sobrescrever esses métodos em sua classe filha, você pode fazer isso fornecendo sua própria implementação. Você pode adicionar suas funções adicionais na classe filha ou você pode adicionar ou modificar a funcionalidade de métodos existentes em sua classe pai. Isso pode ser feito da seguinte maneira: modificar o arquivo 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;

Agora vamos tentar novamente usar o objeto Employee em nosso arquivo main.pl e executá-lo.

#!/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 executamos o programa acima, ele produz o seguinte resultado -

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.

Carregamento automático padrão

Perl oferece um recurso que você não encontraria em nenhuma outra linguagem de programação: uma sub-rotina padrão. O que significa que, se você definir uma função chamadaAUTOLOAD(),então, quaisquer chamadas a sub-rotinas indefinidas chamarão a função AUTOLOAD () automaticamente. O nome da sub-rotina ausente está acessível dentro desta sub-rotina como $ AUTOLOAD.

A funcionalidade de carregamento automático padrão é muito útil para tratamento de erros. Aqui está um exemplo para implementar AUTOLOAD, você pode implementar esta função à sua maneira.

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

Destruidores e coleta de lixo

Se você já programou usando a programação orientada a objetos antes, então você estará ciente da necessidade de criar um destructorpara liberar a memória alocada para o objeto quando você terminar de usá-lo. Perl faz isso automaticamente para você assim que o objeto sai do escopo.

No caso de você querer implementar seu destruidor, que deve cuidar de fechar arquivos ou fazer algum processamento extra, então você precisa definir um método especial chamado DESTROY. Este método será chamado no objeto antes que o Perl libere a memória alocada para ele. Em todos os outros aspectos, o método DESTROY é como qualquer outro método, e você pode implementar qualquer lógica que quiser dentro desse método.

Um método destruidor é simplesmente uma função de membro (sub-rotina) chamada DESTROY, que será chamada automaticamente nos seguintes casos -

  • Quando a variável de referência do objeto sai do escopo.
  • Quando a variável de referência do objeto é indefinida.
  • Quando o script termina
  • Quando o interpretador perl termina

Por exemplo, você pode simplesmente colocar o seguinte método DESTROY em sua classe -

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

Exemplo de Perl Orientado a Objetos

Aqui está outro bom exemplo, que o ajudará a entender os Conceitos Orientados a Objetos do Perl. Coloque este código-fonte em qualquer arquivo perl e execute-o.

#!/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 executamos o programa acima, ele produz o seguinte resultado -

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