next up previous contents index practicapracticaPP2moodleLHPmoodlepserratacpanmodulospauseperlgoogleetsiiullpcgull
Sig: Práctica: Un Módulo OOP Sup: Programación Orientada a Objetos Ant: Programación Orientada a Objetos Err: Si hallas una errata ...


Introducción

Sigue un ejemplo que gestiona una biblioteca:
package Biblio::Doc;
use strict;

{
  my $_count = 0;
  sub get_count { $_count }
  sub _incr_count { $_count++ }
}

sub new {
  my $class = shift;
  my ($identifier, $author, $publisher, $title,  $year, $url) = @_;
  $class->_incr_count();

  my $paper = {
    _identifier      => $identifier,
    _author    => $author,
    _publisher => $publisher,
    _title     => $title,
    _year      => $year,
    _url       => $url
  };

  bless  $paper, $class;
}

sub get_identifier { $_[0]->{_identifier} }
sub get_author { $_[0]->{_author} }
sub get_publisher { $_[0]->{_publisher} }
sub get_title { $_[0]->{_title} }
sub get_year { $_[0]->{_year} }
sub get_url { $_[0]->{_url} }

sub set_url {
  my ($self, $url) = @_;
  $self ->{_url} = $url if $url;
  return ($self ->{_url});
}

1;

La clase Biblio::Doc se implanta a través del package Biblio::Doc

package Biblio::Doc;
use strict;
...
Los paquetes proporcionan un conjunto de características que son comunes a las clases: proporcionan un espacio de nombres separado, agrupando así un código que ofrece un conjunto de funcionalidades relacionadas y aislándolo del resto; tienen un nombre que puede ser usado para identificar los datos y subrutinas en el paquete (fully qualified names) y, si el paquete es un módulo, diferencian entre la parte a exportar y la parte interna. Por todo ello Perl usa los paquetes para implantar las clases.

Obsérvese la clausura creada para el contador de referencias bibliográficas $_count. Este contador es el único atributo de clase en este ejemplo. Los restantes son atributos del objeto.

{
  my $_count = 0;
  sub get_count { $_count }
  sub _incr_count { $_count++ }
}
Es un convenio en Perl que las variables que comienzan con un guión bajo son variables privadas. Consecuencia de este convenio es que debemos entender que el autor pretende que $_count y _incr_count sean privadas.

La variable privada $_count contiene el contador de documentos. Su acceso queda restringido no ya al ámbito del módulo sino al ámbito léxico establecido por la clausura. La única forma de acceder a $_count es a través de las funciones _incr_count y get_count.

En general, en programación orientada a objetos se aconseja que se envuelvan todos los accesos a atributos en subrutinas y se prohiba la posible modificación exterior de los mismos ([14] .

A continuación viene el constructor de objetos new (su nombre es arbitrario, pero la costumbre es llamar así a los constructores) de la clase Biblio::Doc

 1 sub new {
 2   my $class = shift;
 3   my ($identifier, $author, $publisher, $title,  $year, $url) = @_;
 4   $class->_incr_count();
 5 
 6   my $paper = {
 7     _identifier      => $identifier,
 8     _author    => $author,
 9     _publisher => $publisher,
10     _title     => $title,
11     _year      => $year,
12     _url       => $url
13   };
14 
15   bless  $paper, $class;
16 }
Un objeto Perl es un dato que ha sido bendecido con un paquete. La operación de bendición bless toma como primer argumento una referencia y como segundo un nombre de paquete. El argumento ``nombre del paquete'' es opcional: se usará el nombre del package actual si se omite. Una vez que un dato es ``bendecido'' (¿Quizá deberíamos decir ``bautizado como miembro de la clase''?) el dato pasa a ``saber'' a que clase-package pertenece. En el ejemplo se bendice una referencia a un hash. Sin embargo, Perl admite que se bendiga una referencia a cualquier otro tipo de objeto.

Podremos crear el objeto con una llamada como la siguiente:

$obj = Biblio::Doc->new(1, "Asimov", "Bruguera", 
   "Los propios dioses", 1989, "unknown");
o bien usando esta otra sintáxis:
$obj = new Biblio::Doc(1, "Asimov", "Bruguera", 
   "Los propios dioses", 1989, "unknown");

Lo que sucede cuando Perl ve una llamada a una subrutina seguida del nombre de un paquete (new Biblio::Doc) o una llamada con la sintáxis de paquete seguido de flecha seguido de un método (Biblio::Doc->new) es que llama a una subrutina con ese nombre en ese paquete, y le pasa como primer argumento el nombre del paquete. Así, el primer argumento que recibe el constructor new es el nombre de la clase, esto es Biblio::Doc. Así pues la línea 2

  my $class = shift;
Obtiene la clase Biblio::Doc.

La llamada de la línea 4:

$class->_incr_count();
es, por tanto, otro ejemplo de esta forma de llamada. En este caso tenemos además un referenciado simbólico via $class.

El hash referenciado por $paper en las líneas de la 6 a la 13 es bendecido en la línea 15 con el nombre de la clase. Esto establece un campo interno dentro de la representación interna del hash anónimo. En cierto sentido es %$paper quien es bendecido, no $paper. La figura 7.1 ilustra este punto: En la izquierda de la figura aparecen la referencia y el referente antes de la bendición. En la parte de la derecha, después de ejecutar bless $paper, $class. Obsérvese que se ha añadido una marca con el nombre de la clase-paquete que identifica la estructura de datos como un objeto de esa clase.

Figura 7.1: Al bendecir un objeto este es marcado con la clase a la que pertenece
\begin{figure}\centerline{\epsfig{file=bless.eps, height=6cm}}\end{figure}

Una vez que el dato apuntado por la referencia ha sido bendecido, el operador ref aplicado a dicha referencia devuelve el nombre del paquete (esto es, el nombre de la clase) en vez de HASH.

Una comprobación de que quien es bendecido es el dato referido no la referencia la da el siguiente código:

$obj = new Biblio::Doc(1, "Asimov", "Bruguera", 
   "Los propios dioses", 1989, "unknown");
$obj2 = $obj;
print "obj2 es un ",ref($obj2),"\n";

Se imprimirá que obj2 es un Biblio::Doc

Para escribir un método para una clase (package) dada, basta con escribir la correspondiente subrutina dentro del paquete.

Así el método get_author queda descrito mediante la subrutina:

sub get_author { $_[0]->{_author} }
Sin embargo, llamar a Biblio::Doc::get_author como método conlleva una extensión a la sintáxis flecha de Perl. Si se tiene que $obj es una referencia a un objeto de la clase Biblio::Doc, podemos acceder a cualquier método del paquete usando la notación $obj->method donde method es cualquier método de la clase. Por ejemplo:
$obj->get_author()
Es equivalente a
Biblio::Doc::get_author($obj);
Esto es: cuando una subrutina es llamada como método, la lista de argumentos que recibe comienza con la referencia al objeto a través del cual fué llamada y va seguida de los argumentos que fueron explicitados en la llamada al método.

Observe que la última llamada trata a get_author como una subrutina ordinaria, mientras que la primera la usa ``como método''.

La sintáxis ``flecha'' para la llamada a un método es consistente con el uso de la flecha para otros tipos de referencias en Perl. Así, al igual que escribimos $hsh_ref->{clave} o bien $sub_ref->(4,7,8) también escribimos $obj_ref->metodo(@args). Una diferencia de esta última notación con las anteriores estriba en que el referente tiene diferentes conductas, esto es, tiene varios metodos y la conducta concreta que queremos producir se especifica escribiendo el nombre del método después de la flecha.

Un método que es invocado a través de un objeto vía $obj_ref->metodo(@args) (por oposición a un objeto de clase que es aquel que es invocado vía una clase/paquete Class->metodo(@args)) se denomina un método dinámico o método de objeto.

Nótese el uso de los prefijos get_ y set_ utilizados para establecer el tipo de acceso al atributo. Un método a través del cual se accede a un atributo recibe el nombre de accesor. Un método que permite modificar el estado interno de un atributo se denomina mutator.

Un programador C se sentiría tentado de usar prototipos para especificar mas claramente el tipo de acceso a un método. Perl no comprueba prototipos cuando una subrutina de paquete es llamada como método, utilizando la sintáxis $objref->method(@args). En el caso mas general resulta imposible conocer hasta el momento de la ejecución que subrutina debe ser invocada en respuesta a una llamada de un método.



Subsecciones
next up previous contents index practicapracticaPP2moodleLHPmoodlepserratacpanmodulospauseperlgoogleetsiiullpcgull
Sig: Práctica: Un Módulo OOP Sup: Programación Orientada a Objetos Ant: Programación Orientada a Objetos Err: Si hallas una errata ...
Casiano Rodríguez León
2006-02-21