package A; @ISA = ( "B" );indica que la clase
A
hereda de la clase B
.
Una alternativa mas breve es usar el módulo base:
use base qw(B C);
La herencia en Perl determina el recorrido de búsqueda de un método. Si el objeto
no se puede encontrar en la clase, recursivamente y en orden primero-profundo
se busca en las clases de las cuales esta hereda, esto es en las clases
especificadas en el vector @ISA
.
Para ser mas precisos, cuando Perl busca por una llamada a un método como
$obj->method()
, realiza la siguiente secuencia de búsqueda:
MyClass
) tiene
una subrutina method
se llama
@ISA
, para cada una de las clases en el vector @ISA
se repiten los pasos 1 y 2
UNIVERSAL
(véase la sección 6.5)
tiene un método con ese nombre, se le llama
MyClass
tiene un método AUTOLOAD
se le llama
AUTOLOAD
, se le llama
UNIVERSAL
tiene un método AUTOLOAD
, se le llama
Esta búsqueda sólo se hace una vez por método. Una vez localizado el método
se utiliza una ''cache'' para acceder al método rápidamente.
Si el vector @ISA
o el vector @ISA
de cualquiera de los antepasados de la clase
es modificado, se limpia la ''cache''.
Como vemos existe una clase especial denominada clase UNIVERSAL de la cual implícitamente hereda toda clase. Esta clase provee los métodos isa, can y VERSION (véase la sección 5.6). Es posible añadir métodos o atributos a UNIVERSAL.
El método isa nos permite saber si una clase hereda de otra:
if ($a->isa("B")) { # El objeto a es de la clase B ... }El método
isa
memoriza los valores que retorna, de manera que una vez que
conoce un par no necesita realizar una segunda búsqueda. Sin embargo la modificación
de los arrays @ISA
en la jerarquía borra las caches:
DB<1> @A::ISA = qw{B}; @B::ISA = qw(C); @C::ISA = () DB<2> $x = bless {}, 'A' DB<3> x $x->isa('C') 0 1 DB<4> @B::ISA = () DB<5> x $x->isa('C') 0 ''
Hay ocasiones en las que lo que nos preocupa no es tanto a que clase pertenece un objeto
como saber si dispone de un cierto método. El método can
devuelve
verdadero si el objeto puede llamar al método solicitado:
if ($a->can("display_object")) { # el objeto dispone del método ... }
De hecho, el valor que devuelve can
es una referencia al método
por el que se pregunta.
Un método singleton es uno que se aplica a un objeto particular y no a toda la clase.
El ejemplo que sigue ilustra la idea de usar singletons.
Aunque los objetos $a
y $b
pertenecen a la misma
clase, sólo el objeto $a
dispone del método dump
.
Para crear un método singleton usamos el método singleton_method
.
Puesto que queremos que todo objeto pueda crear sus métodos
singleton debemos ubicar singleton_method
en la clase
UNIVERSAL
.
hp@nereida:~/Lperl/src/advanced_perl_programming2$ cat -n singleton.pl 1 #!/usr/local/bin/perl -w 2 use strict; 3 use Class::SingletonMethod; 4 5 my $a = Some::Class->new(yuyu => 4, chuf => [ 1..5]); 6 my $b = Some::Class->new(yuyu => 8, chuf => [0..9]); 7 8 $a->singleton_method( dump => sub { 9 my $self = shift; 10 require Data::Dumper; 11 no warnings; 12 $Data::Dumper::Indent = 0; 13 print STDERR Data::Dumper::Dumper($self)."\n" 14 }); 15 16 $a->dump; # Prints a representation of the object. 17 $b->dump; # Can't locate method "dump" 18 19 package Some::Class; 20 21 sub new { 22 my $class = shift; 23 24 bless { @_ }, $class; 25 }
lhp@nereida:~/Lperl/src/advanced_perl_programming2$ singleton.pl $VAR1 = bless( {'chuf' => [1,2,3,4,5],'yuyu' => 4}, '_Singletons::135852824' ); Can't locate object method "dump" via package "Some::Class" at ./singleton.pl line 17.
El método singleton_method
crea una clase
para el objeto que hace la invocación
- si no fué creada anteriormente -
y hace que esta nueva clase herede de
la clase del objeto.
El algoritmo garantiza que objetos distintos tendrán clases
distintas.
lhp@nereida:~/Lperl/src/advanced_perl_programming2$ sed -ne '9,23p' `perldoc -l Class::SingletonMethod` | cat -n 1 package UNIVERSAL; 2 3 no warnings; no strict; # no guarantee 4 5 sub singleton_method { 6 my ($object, $method, $subref) = @_; 7 8 my $parent_class = ref $object; 9 my $new_class = "_Singletons::".(0+$object); 10 *{$new_class."::".$method} = $subref; 11 if ($new_class ne $parent_class) { 12 @{$new_class."::ISA"} = ($parent_class); 13 bless $object, $new_class; 14 } 15 }
nereida:~/doc/casiano/PLBOOK/PLBOOK> perl -wde 0 main::(-e:1): 0 DB<1> $x = {} DB<2> p $x HASH(0x8150634) DB<3> $y =$x+0 DB<4> p $y 135595572 DB<5> printf "%x",$y 8150634