Llamando al constructor base en perl
oop (3)
Cuando se utiliza la herencia múltiple, el orden de resolución del método predeterminado es subpar. Te recomiendo que agregues
use mro ''c3'';
a los módulos y que llamas al siguiente constructor en la cadena usando
sub new {
my ($class) = @_;
return $class->next::method(@_);
}
Alpha y Beta tendrían que hacer lo mismo para que esto funcione.
Ref: mro
¿Cuál es la forma correcta de llamar al constructor base desde el constructor de la clase en Perl?
He visto una sintaxis como esta:
my $class = shift;
my $a = shift;
my $b = shift;
my $self = $class->SUPER::new($a, $b);
return $self;
Es esto correcto ? ¿Qué pasa si tenemos varias clases para padres. Por ejemplo, una clase como esta:
package Gamma;
use base Alpha;
use base Beta;
sub new
{
# Call base constructors...
}
1;
Este problema es por lo que algunas personas recomiendan no hacer nada interesante en su new
método. se espera que lo nuevo cree y devuelva una referencia bendita, es difícil hacer un sistema que maneje hacer esto dos veces para el mismo objeto de diferentes clases primarias.
Una opción más limpia es tener un nuevo método que solo cree el objeto y llame a otro método que pueda configurar el objeto. Este segundo método puede comportarse de una manera que permita llamar a múltiples métodos principales. Efectivamente new
es su asignador y este otro método es su constructor.
package Mother;
use strict;
use warnings;
sub new {
my ($class, @args) = @_;
my $self = bless {}, $class;
return $self->_init(@args);
}
sub _init {
my ($self, @args) = @_;
# do something
return $self;
}
package Father;
use strict;
use warnings;
sub new {
my ($class, @args) = @_;
my $self = bless {}, $class;
return $self->_init(@args);
}
sub _init {
my ($self, @args) = @_;
# do something else
return $self;
}
package Child;
use strict;
use warnings;
use base qw(Mother Father);
sub _init {
my ($self, @args) = @_;
# do any thing that needs to be done before calling base classes
$self->Mother::_init(@args); # Call Mother::_init explicitly, SUPER::_init would also call Mother::_init
$self->Father::_init(@args); # Call Father::_init explicitly, SUPER::_init would NOT call Father::_init
# do any thing that needs to be done after calling base classes
return $self;
}
Ether tiene razón acerca de las complicaciones que probablemente encuentre al usar la herencia múltiple. Aún necesita saber que el Father::_init
no anulará ninguna decisión tomada por la Mother::_init
para comenzar. Solo se volverá más complicado y más difícil de depurar desde allí.
Me gustaría secundar la recomendación de Moose , su interfaz incluye una mejor separación de la creación e inicialización del objeto que mi ejemplo anterior, que por lo general solo funciona.
Si todo lo que está haciendo su constructor es llamar al constructor primario (como en su ejemplo, no necesita escribir uno en absoluto. Simplemente omítalo y se llamará al padre; solo debe asegurarse de que el objeto sea bendecido en el tipo correcto:
package Parent;
use strict;
use warnings;
sub new
{
my ($class, @args) = @_;
# do something with @args
return bless {}, $class;
}
1;
Si usa el código anterior y tiene una clase Child
declarada con el use parent ''Parent'';
entonces el constructor padre construirá correctamente un hijo.
Si necesita agregar algunas propiedades en el hijo, entonces lo que tenía es en gran parte correcto:
package Child;
use strict;
use warnings;
use parent ''Parent'';
sub new
{
my ($class, @args) = @_;
# possibly call Parent->new(@args) first
my $self = $class->SUPER::new(@args);
# do something else with @args
# no need to rebless $self, if the Parent already blessed properly
return $self;
}
1;
Sin embargo, cuando introduce la herencia múltiple en la mezcla, debe decidir qué hacer en cada paso del camino. Esto significa un constructor personalizado para cada clase que decide cómo fusionar las propiedades de Parent1 y Parent2 en el hijo, y luego, finalmente, bendice el objeto resultante en la clase Child. Esta complicación es una de las muchas razones por las cuales la herencia múltiple es una mala elección de diseño. ¿Ha considerado rediseñar la jerarquía de sus objetos, posiblemente moviendo algunas propiedades a roles? Además, es posible que desee emplear un marco de objeto para eliminar parte del trabajo ocupado, como Moose . Hoy en día rara vez es necesario escribir un constructor personalizado.
(Por último, debe evitar el uso de las variables $a
y $b
; se tratan de manera diferente en Perl, ya que son las variables que se usan en las funciones de clasificación y algunas otras funciones integradas).