next up previous contents index practicapracticaPP2moodleLHPmoodlepserratacpanmodulospauseperlgoogleetsiiullpcgull
Sig: Copia de Objetos Sup: Programación Orientada a Objetos Ant: Práctica: Instalación Automática de Err: Si hallas una errata ...


Constructores

Se suelen llamar constructores a aquellos métodos de la clase que asignan memoria para la estructura de datos en la que subyace el nuevo objeto, inicializándolo y bendiciéndolo. A la hora de escribir un constructor es conveniente tener en cuenta los siguientes puntos:
  1. Lo habitual es que el nombre de un constructor sea new.
  2. Es conveniente escribir el proceso de inicialización en un método privado separado que es llamado desde el constructor.
  3. Es habitual que los constructores tengan muchos parámetros. Es conveniente utilizar la estrategia explicada en la subsección 1.9.8 de usar un hash para proveer paso de argumentos con nombre.
  4. Adicionalmente, es necesario proveer valores por defecto en la inicialización, de manera que campos no especificados por el usuario resulten inicializados de manera apropiada.
  5. Se suele distinguir entre atributos de ``sólo lectura'' y atributos de ``lectura/escritura'', controlando el tipo de acceso que el programa cliente hace al atributo.
A continuación veamos un código que, siguiendo las recomendaciones establecidas, separa el proceso de iniciación, organiza los parámetros del constructor según un ``hash'' y provee valores por defecto:
 1	package Biblio::Doc;
 2	use strict;
 3	use vars('$AUTOLOAD');
 4	
 5	# Separamos inicialización de construcción 
 6	
 7	{
 8	  my $_count = 0;
 9	  sub get_count { $_count }
10	  sub _incr_count { $_count++ }
11	  sub _decr_count { $_count-- }
12	}
13	
14	{
15	  my %_defaults = (             #   Default   Access 
16	                    _identifier => ["unknown",'read'],
17	                    _author     => ["unknown",'read/write'],
18	                    _publisher  => ["unknown",'read'],
19	                    _title      => ["unknown",'read'],
20	                    _year       => ["unknown",'read'],
21	                    _url        => ["unknown",'read/write']
22	                  );
Se ha introducido un hash que contiene los valores por defecto y el tipo de acceso permitio (lectura/escritura) para cada clave.
24	  sub _standard_keys {
25	    return keys %_defaults;
26	  }
Queremos además disponer de un método que nos diga que claves forman el objeto. Esa es la función del método privado _standard_keys.
28	  sub _default_for {
29	    my ($self, $attr) = @_;
30	    
31	    return $_defaults{$attr}[0];
32	  }
33	
34	  sub _accesible {
35	    my ($self, $attr, $access) = @_;
36	    return $_defaults{$attr}[1] =~ /$access/;
37	  }
El método _default_for permite acceder al valor por defecto. El método _accesible nos dice si una clave esta accesible para el tipo de acceso requerido.
39	  sub _init {
40	    my ($self, %args) = @_;
41	    my %inits;
42	    my ($i, $j);
43	
44	    for $i ($self->_standard_keys) {
45	      $j = $i;
46	      $j =~ s/_//;
47	      $inits{$i} = $args{$j} || $self->_default_for($i);
48	    }
49	    %$self = %inits;
50	  }
51	}
El método privado _init inicializa el hash referenciado por $self según lo indicado en el hash %args. Las claves en %args no van precedidas de guión bajo (se supone que la llamada desde el programa cliente usará los nombres de los atributos sin guión bajo). Si la clave no figura en %args se inicializa al valor por defecto. Observe que el uso de $self->_standard_keys en el bucle de la línea 44 nos protege contra errores de inicializaciones con claves inexistentes en el objeto, posiblemente como consecuencia de un error en la llamada desde el cliente (quizá debidos a un error tipográfico).

53	sub new {
54	  my $class = shift;
55	  my $self = {};
56	
57	  bless $self, ref($class) || $class;
58	
59	  $self->_incr_count();
60	  $self->_init(@_);
61	
62	  return $self;
63	}
En la línea 57 se bendice el objeto aún sin inicializar. Cuando el constructor es llamado mediante Biblio::Doc->new() la variable $class contendrá la cadena 'Biblio::Doc' por lo que ref($class) devuelve undef y $self será bendecido en 'Biblio::Doc'. La línea 57 esta escrita pensando que el constructor pueda ser llamado de la forma $x->new donde $x es un objeto de la clase Biblio::Doc. Como sabemos, en tal caso ref($x) contendrá la cadena 'Biblio::Doc'. Asi pues, $self será, también en este caso, bendecido en 'Biblio::Doc'.

Observe como hemos desacoplado la inicialización de la creación y bendición de la estructura. Es posible que durante el periodo de desarrollo del módulo la estructura del hash cambie, introduciendo nuevos atributos o suprimiendo algunos existentes. Con el desacoplado conseguimos que estos cambios no afecten a new (aunque si a _init).

65	sub DESTROY {
66	  my $self = shift;
67	
68	  $self->_decr_count();
69	}
Perl elimina automáticamente la memoria de un objeto cuando es claro que ya no va a ser utilizado. Un método con el nombre especial DESTROY se dispara cuando la memoria asociada con un objeto debe ser eliminada (normalmente por que salimos de su ámbito de existencia).
71	sub AUTOLOAD {
72	  no strict "refs";
73	  my $self = shift;
74	  if (($AUTOLOAD =~ /\w+::\w+::get(_.*)/) && ($self->_accesible($1,'read'))) {
75	    my $n = $1;
76	    return unless exists $self->{$n};
77	
78	    # Declarar el metodo get_*****
79	    *{$AUTOLOAD} = sub { return "(nuevo get) ".$_[0]->{$n}; };
80	
81	    return "(autoload) ".$self->{$n};
82	  } elsif (($AUTOLOAD =~ /\w+::\w+::set(_.*)/) && ($self->_accesible($1,'write'))) {
83	    my $n = $1;
84	    return unless exists $self->{$n};
85	    $self->{$n} = "(autoload) ".shift;
86	
87	    # Declarar el metodo set_*****
88	    *{$AUTOLOAD} = sub { $_[0]->{$n} = "(nuevo set) ".$_[1]; };
89	  } else {
90	    @_ = map { "\"".$_."\""; } @_;   # Comillas a los argumentos...
91	    print "Has llamado a $AUTOLOAD(",join(", ",@_),")\n";
92	  }
93	}
94	
95	1;
También hemos extendido la subrutina AUTOLOAD para que compruebe (líneas 74 y 82) que el método de acceso requerido está permitido.


next up previous contents index practicapracticaPP2moodleLHPmoodlepserratacpanmodulospauseperlgoogleetsiiullpcgull
Sig: Copia de Objetos Sup: Programación Orientada a Objetos Ant: Práctica: Instalación Automática de Err: Si hallas una errata ...
Casiano Rodríguez León
2006-02-21