2011-03-09 16 views
17

Perl'de sınıf yapıcısından temel yapıcıyı çağırmanın doğru yolu nedir?Perl'de temel yapıcı çağırma

böyle sözdizimi gördük:

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

Bu doğru mu? Ya birden fazla üst sınıfımız varsa. Örneğin böyle bir sınıfı:.

package Gamma; 
use base Alpha; 
use base Beta; 

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

cevap

18

Bu sorun neden bazı insanlar new yönteminizde ilginç bir şey yapmamanızı öneririz. new'un kutsanmış bir başvuru oluşturması ve döndürmesi beklenir; bu, farklı nesne sınıflarından aynı nesne için bunu iki kez gerçekleştiren bir sistem oluşturmak zor olur.

Daha temiz bir seçenek, yalnızca nesneyi oluşturan ve nesneyi oluşturabilecek başka bir yöntemi çağırmak için yeni bir yönteme sahip olmaktır. Bu ikinci yöntem, birden çok üst yöntemin çağrılmasına izin verecek şekilde davranabilir. Etkili new siz ayırdediciniz ve bu diğer yöntem sizin kurucunuz.

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

Eter, birden fazla kalıtım kullanarak bulmanız olası karmaşıklıklarla ilgili haklıdır. Yine de, Father::_init'un, başlamak için Mother::_init tarafından verilen tüm kararları geçersiz kılmayacağını bilmeniz gerekir. Oradan ayıklamak sadece daha karmaşık ve daha zor olacak.

Moose numaralı öneriye başvurmak isterim; arabirimi, nesne oluşturma ve başlatma işleminin daha iyi bir şekilde ayrılmasını ve yukarıdaki örnekte yaptığımdan genellikle işe yarar.

+0

sayesinde bu işleri şeye benim şimdiki kod dönüştürmek için en kolay yolu gibi görünüyor. – Zitrax

30

tüm yapıcı sizin örnekte olduğu gibi ana yapıcısı (çağırıyor yapıyor ise, hiç bir yazmak gerekmez Basitçe dışarı bırakın ve ebeveyn olacak çağrılabilir; sadece nesne sağ türü içine kutsanmış sağlamak gerekir: yukarıdaki kodu kullanabilirsiniz ve bir Child sınıf use parent 'Parent'; ile beyan varsa

package Parent; 
use strict; 
use warnings; 

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

    # do something with @args 

    return bless {}, $class; 
} 
1; 

sonra Veli yapıcı düzgün bir çocuk inşa edecek

.

Eğer Çocukta bazı özelliklerini eklemek gerekir, o zaman ne vardı ölçüde doğrudur:

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; 

Ancak, doğru olanı karar vermek gerek her adımda yapmak karışımı içine birden devralma getirdiklerinde yolun Bu, Parent1 ve Parent2'nin özelliklerinin çocuğa nasıl birleştirileceğine karar veren her sınıf için özel bir kurucu anlamına gelir ve sonuçta ortaya çıkan nesneyi Çocuk sınıfına verir. Bu komplikasyon, çoklu kalıtımın kötü bir tasarım tercihi olmasının birçok nedenlerinden biridir. Nesnelerin heirarşisini, muhtemelen bazı özellikleri rollere taşıyarak, yeniden tasarlamayı düşündünüz mü? Dahası, Moose gibi yoğun işlerden bazılarını çıkarmak için bir nesne çerçevesi kullanmak isteyebilirsiniz. Bugünlerde özel bir kurucu yazmak için nadiren gereklidir.

(Son olarak, değişkenler $a ve $b kullanmaktan kaçınmalısınız, onlar sıralama işlevlerinde kullanılan değişkenler ve diğer bazı yerleşik ins gibi onlar Perl farklı şekilde işlenir.)

5

Birden çok devralma kullanıldığında, varsayılan yöntem çözümleme sırası alt par.Şiddetle modülleri

use mro 'c3'; 

ekleyin ve

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

Alfa kullanmaya zincirin bir sonraki kurucusunu çağırmak ve Beta bunun işe yaraması için aynı şeyi gerekir öneririz.

Ref: mro