2011-03-09 70 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

相關問題