Delegación en la Inicialización

Cuando existe una jerarquía de herencia, es común un diseño que usa una delegación planificada en las clases antecesoras. Una solución consiste en separar la creación del objeto de su inicialización. Esto es: el código de un inicializador llama a los correspondientes inicializadores de las clases antepasadas y añade las correspondientes inicializaciones de la clase.

Estudie este ejemplo:

 1 #!/usr/bin/perl -d
 2 
 3 package _I;
 4 use strict;
 5 
 6 sub new {
 7   my ($class, %args) = @_;
 8   my $self = bless {}, ref($class) || $class;
 9   $self->_init(%args);
10   return $self;
11 }
12 
13 package A;
14 @A::ISA = qw( _I);
15 
16 sub _init {
17   my ($self, %args) = @_;
18   $self->{_a1} = $args{a1};
19   $self->{_a2} = $args{a2};
20 }
21 
22 
23 package B;
24 @B::ISA = qw( _I);
25 
26 sub _init {
27   my ($self, %args) = @_;
28   $self->{_b1} = $args{b1};
29 }
30 
31 package C;
32 @C::ISA = qw( _I B A);
33 
34 sub _init {
35   my ($self, %args) = @_;
36   $self->A::_init(%args);
37   $self->B::_init(%args);
38   $self->{_c1} = $args{c1};
39 }
40 
41 package main;
42 
43 C->new(a1=>"a1", a2=>"a2", b1=>"b1", c1=>"c1");
La idea es que la clase _I provee un constructor genérico. Las otras clases heredan dicho constructor y no lo reescriben. La figura 6.3 muestra el esquema de herencia y el de delegación (flechas punteadas) usado para el método _init.
Figura: Esquema de herencia/delegación del programa
\begin{figure}\centerline{\epsfig{file=delegation.eps, height=6cm}}\end{figure}

Este esquema es posiblemente mas usual que el reemplazamiento completo del método por uno nuevo.

Véase una ejecución con el depurador:

$ ./inicializadores.pl
Default die handler restored.

Loading DB routines from perl5db.pl version 1.07
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

A::(./inicializadores.pl:14):   @A::ISA = qw( _I);
  DB<1> n
B::(./inicializadores.pl:24):   @B::ISA = qw( _I);
  DB<1>
C::(./inicializadores.pl:32):   @C::ISA = qw( _I B A);
  DB<1>
main::(./inicializadores.pl:43):        C->new(a1=>"a1", a2=>"a2", b1=>"b1", c1=>"c1");
el método new en la clase _I acaba siendo llamado:
  DB<1> s
_I::new(./inicializadores.pl:7):          my ($class, %args) = @_;
  DB<1>
_I::new(./inicializadores.pl:8):          my $self = bless {}, ref($class) || $class;
  DB<1> p $class
C
  DB<2> n
_I::new(./inicializadores.pl:9):          $self->_init(%args);
Obsérvese que:
  DB<2> s
C::_init(./inicializadores.pl:35):        my ($self, %args) = @_;
  DB<2>
C::_init(./inicializadores.pl:36):        $self->A::_init(%args);
Las llamadas en las líneas 36 y 37 explicitan el paquete: $self->A::_init(%args) y $self->B::_init(%args). Normalmente, cuando Perl comienza la busca en el paquete en el cual ha sido bendecido el objeto, pero si en la llamada con el operador flecha se detalla el nombre completo del método (fully qualified name) Perl ignora la clase del objeto y comienza la búsqueda en la tabla de símbolos del paquete prefijo.
  DB<2>
A::_init(./inicializadores.pl:17):        my ($self, %args) = @_;
  DB<2>
A::_init(./inicializadores.pl:18):        $self->{_a1} = $args{a1};
  DB<2>
A::_init(./inicializadores.pl:19):        $self->{_a2} = $args{a2};
  DB<2>
C::_init(./inicializadores.pl:37):        $self->B::_init(%args);
  DB<2>
B::_init(./inicializadores.pl:27):        my ($self, %args) = @_;
  DB<2>
B::_init(./inicializadores.pl:28):        $self->{_b1} = $args{b1};
  DB<2>
C::_init(./inicializadores.pl:38):        $self->{_c1} = $args{c1};
  DB<2>
_I::new(./inicializadores.pl:10):         return $self;
  DB<2> p %$self
_a2a2_b1b1_c1c1_a1a1
  DB<3>
Debugged program terminated.  Use q to quit or R to restart,
  use O inhibit_exit to avoid stopping after program termination,
  h q, h R or h O to get additional info.
El proceso de destrucción es equivalente. Puesto que se trata de métodos, se sigue el mismo algoritmo de búsqueda. Si queremos que los destructores sean llamados de manera organizada, es responsabilidad del programador el hacerlo.

Casiano Rodríguez León
Licencia de Creative Commons
Principios de Programación Imperativa, Funcional y Orientada a Objetos Una Introducción en Perl/Una Introducción a Perl
por Casiano Rodríguez León is licensed under a Creative Commons Reconocimiento 3.0 Unported License.

Permissions beyond the scope of this license may be available at http://campusvirtual.ull.es/ocw/course/view.php?id=43.
2012-06-19