Programación orientada a objetos en PERL

Ya hemos estudiado referencias en matrices y hashes anónimos de Perl y Perl. El concepto orientado a objetos en Perl se basa en gran medida en referencias y matrices anónimas y hashes. Comencemos a aprender los conceptos básicos de Perl orientado a objetos.

Conceptos básicos de los objetos

Hay tres términos principales, explicados desde el punto de vista de cómo Perl maneja los objetos. Los términos son objeto, clase y método.

  • Un objectdentro de Perl es simplemente una referencia a un tipo de datos que sabe a qué clase pertenece. El objeto se almacena como referencia en una variable escalar. Debido a que un escalar solo contiene una referencia al objeto, el mismo escalar puede contener diferentes objetos en diferentes clases.

  • UN class Dentro de Perl hay un paquete que contiene los métodos correspondientes necesarios para crear y manipular objetos.

  • UN methoddentro de Perl hay una subrutina, definida con el paquete. El primer argumento del método es una referencia de objeto o un nombre de paquete, dependiendo de si el método afecta al objeto actual oa la clase.

Perl proporciona una bless() función, que se utiliza para devolver una referencia que finalmente se convierte en un objeto.

Definiendo una clase

Es muy sencillo definir una clase en Perl. Una clase corresponde a un paquete Perl en su forma más simple. Para crear una clase en Perl, primero construimos un paquete.

Un paquete es una unidad autónoma de variables y subrutinas definidas por el usuario, que se puede reutilizar una y otra vez.

Los paquetes de Perl proporcionan un espacio de nombres separado dentro de un programa de Perl que mantiene las subrutinas y variables independientes de entrar en conflicto con las de otros paquetes.

Para declarar una clase llamada Persona en Perl, hacemos:

package Person;

El alcance de la definición del paquete se extiende hasta el final del archivo o hasta que se encuentre otra palabra clave del paquete.

Crear y usar objetos

Para crear una instancia de una clase (un objeto) necesitamos un constructor de objetos. Este constructor es un método definido dentro del paquete. La mayoría de los programadores eligen nombrar este método constructor de objetos como nuevo, pero en Perl puede usar cualquier nombre.

Puede utilizar cualquier tipo de variable de Perl como objeto en Perl. La mayoría de los programadores de Perl eligen referencias a matrices o hashes.

Creemos nuestro constructor para nuestra clase Person usando una referencia hash de Perl. Al crear un objeto, debe proporcionar un constructor, que es una subrutina dentro de un paquete que devuelve una referencia de objeto. La referencia de objeto se crea bendiciendo una referencia a la clase del paquete. Por ejemplo

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

Ahora veamos cómo crear un objeto.

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

Puede usar hash simple en su constructor si no desea asignar ningún valor a ninguna variable de clase. Por ejemplo

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

Definición de métodos

Otros lenguajes orientados a objetos tienen el concepto de seguridad de los datos para evitar que un programador cambie los datos de un objeto directamente y proporcionan métodos de acceso para modificar los datos del objeto. Perl no tiene variables privadas, pero aún podemos usar el concepto de métodos auxiliares para manipular datos de objetos.

Definamos un método auxiliar para obtener el nombre de la persona -

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

Otra función auxiliar para establecer el nombre de la persona:

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

Ahora echemos un vistazo al ejemplo completo: Mantenga el paquete Person y las funciones auxiliares en el archivo 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;

Ahora hagamos uso del objeto Person en el archivo employee.pl de la siguiente manera:

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

Cuando ejecutamos el programa anterior, produce el siguiente resultado:

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

Herencia

La programación orientada a objetos tiene un concepto muy bueno y útil llamado herencia. La herencia simplemente significa que las propiedades y métodos de una clase principal estarán disponibles para las clases secundarias. Para que no tenga que escribir el mismo código una y otra vez, solo puede heredar una clase principal.

Por ejemplo, podemos tener una clase Empleado, que hereda de Persona. Esto se conoce como una relación "isa" porque un empleado es una persona. Perl tiene una variable especial, @ISA, para ayudar con esto. @ISA gobierna la herencia (método).

Los siguientes son los puntos importantes que se deben considerar al usar la herencia:

  • Perl busca en la clase del objeto especificado el método o atributo dado, es decir, variable.

  • Perl busca las clases definidas en la matriz @ISA de la clase de objeto.

  • Si no se encuentra ningún método en los pasos 1 o 2, Perl usa una subrutina AUTOLOAD, si se encuentra alguna en el árbol @ISA.

  • Si aún no se puede encontrar un método coincidente, Perl busca el método dentro de la clase (paquete) UNIVERSAL que viene como parte de la biblioteca estándar de Perl.

  • Si el método aún no se encuentra, Perl se rinde y genera una excepción de tiempo de ejecución.

Entonces, para crear una nueva clase de Empleado que heredará métodos y atributos de nuestra clase de Persona, simplemente codificamos de la siguiente manera: Mantenga este código en Employee.pm.

#!/usr/bin/perl

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

Ahora Employee Class tiene todos los métodos y atributos heredados de la clase Person y puede usarlos de la siguiente manera: Use el archivo main.pl para probarlo -

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

Cuando ejecutamos el programa anterior, produce el siguiente resultado:

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

Anulación de método

La clase hijo Employee hereda todos los métodos de la clase padre Person. Pero si desea anular esos métodos en su clase secundaria, puede hacerlo dando su propia implementación. Puede agregar sus funciones adicionales en la clase secundaria o puede agregar o modificar la funcionalidad de un método existente en su clase principal. Se puede hacer de la siguiente manera: modificar el archivo 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;

Ahora intentemos de nuevo usar el objeto Empleado en nuestro archivo main.pl y ejecutarlo.

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

Cuando ejecutamos el programa anterior, produce el siguiente 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.

Carga automática predeterminada

Perl ofrece una característica que no encontraría en ningún otro lenguaje de programación: una subrutina predeterminada. Lo que significa que si define una función llamadaAUTOLOAD(),luego, cualquier llamada a subrutinas indefinidas llamará a la función AUTOLOAD () automáticamente. El nombre de la subrutina que falta es accesible dentro de esta subrutina como $ AUTOLOAD.

La función de carga automática predeterminada es muy útil para el manejo de errores. Aquí hay un ejemplo para implementar AUTOLOAD, puede implementar esta función a su manera.

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

Destructores y recolección de basura

Si ha programado utilizando programación orientada a objetos anteriormente, entonces será consciente de la necesidad de crear un destructorpara liberar la memoria asignada al objeto cuando haya terminado de usarlo. Perl hace esto automáticamente por usted tan pronto como el objeto se sale de su alcance.

En caso de que desee implementar su destructor, que debería encargarse de cerrar archivos o hacer algún procesamiento adicional, entonces necesita definir un método especial llamado DESTROY. Este método se llamará en el objeto justo antes de que Perl libere la memoria asignada. En todos los demás aspectos, el método DESTROY es como cualquier otro método, y puede implementar cualquier lógica que desee dentro de este método.

Un método destructor es simplemente una función miembro (subrutina) llamada DESTROY, que se llamará automáticamente en los siguientes casos:

  • Cuando la variable de referencia del objeto queda fuera de alcance.
  • Cuando la variable de referencia del objeto no está definida.
  • Cuando termina el guión
  • Cuando termina el intérprete de perl

Por ejemplo, simplemente puede poner el siguiente método DESTROY en su clase:

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

Ejemplo de Perl orientado a objetos

Aquí hay otro buen ejemplo, que le ayudará a comprender los conceptos de Perl orientados a objetos. Coloque este código fuente en cualquier archivo perl y ejecútelo.

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

Cuando ejecutamos el programa anterior, produce el siguiente 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