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.
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.