2011-03-09 132 views
17

从Perl的类构造函数中调用基构造函数的正确方法是什么?在perl中调用基构造函数

我见过的语法是这样的:

my $class = shift; 
my $a = shift; 
my $b = shift; 
my $self = $class->SUPER::new($a, $b); 
return $self; 

这是正确的吗?如果我们有几个父类,该怎么办?例如像这样的类:

package Gamma; 
use base Alpha; 
use base Beta; 

sub new 
{ 
    # Call base constructors... 
} 
1; 

回答

18

这个问题就是为什么有些人建议不要在您的new方法中做任何有趣的事情。 new预计会创建并返回一个幸运的引用,但很难让系统为来自不同父类的同一对象处理两次这样的操作。

更简洁的选项是有一个新的方法,只创建对象并调用另一个可以设置对象的方法。第二种方法的行为可以允许调用多个父方法。有效的new是你的分配器,而这个其他的方法是你的构造函数。

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; 
} 

以太是正确的,你可能发现使用多重继承的复杂性。您仍然需要知道Father::_init不会覆盖Mother::_init开始的任何决定。从那里调试只会变得更加复杂和困难。

我会第二个Moose的建议,它的接口包括一个更好的分离对象的创建和初始化比我上面的例子,通常只是工作。

+0

谢谢,这似乎是我当前的代码转换成一些作品的最简单的方法。 – Zitrax 2011-03-10 15:32:25

30

如果你的所有构造函数做的是调用父类的构造(如在你的榜样,你不需要写一个都简单地离开它和家长会叫,你只需要确保的对象是有福到正确的类型:

package Parent; 
use strict; 
use warnings; 

sub new 
{ 
    my ($class, @args) = @_; 

    # do something with @args 

    return bless {}, $class; 
} 
1; 

如果使用上面的代码,并与use parent 'Parent';宣布Child类,则父类的构造将正常构造一个孩子

如果你需要在孩子添加一些属性,然后你有什么在很大程度上是正确的:

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; 

但是,当你把多重继承混进去,需要决定正确的事情的每一步做的方式。这意味着每个类的自定义构造函数决定如何将Parent1和Parent2的属性合并到子级中,然后最终将生成的对象加入到Child类中。这种并发症是多重继承是一个糟糕的设计选择的原因之一。你有没有考虑重新设计你的对象层次,可能是通过将一些属性转换为角色?此外,您可能希望使用对象框架来取出一些繁忙的工作,如Moose。现在很少需要编写自定义构造函数。

(最后,你应该避免使用变量$a$b,他们的处理方式不同在Perl,因为他们在排序函数中使用的变量和其他一些内置插件。)

5

使用多重继承时,默认的方法解析顺序是次级参数。我强烈建议你添加

use mro 'c3'; 

的模块和您在使用

sub new { 
    my ($class) = @_; 
    return $class->next::method(@_); 
} 

阿尔法调用链中的下一个构造函数和Beta将不得不为这个工作做。

编号:mro

相关问题