2011-03-09 14 views
17

में बेस कन्स्ट्रक्टर को कॉल करना पर्ल में कक्षा कन्स्ट्रक्टर से बेस कन्स्ट्रक्टर को कॉल करने का सही तरीका क्या है?पर्ल

मैं इस तरह वाक्य रचना को देखा है:

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::_initMother::_init द्वारा शुरू किए गए किसी भी निर्णय को ओवरराइड नहीं करेगा। यह केवल वहां से डीबग करने के लिए और अधिक जटिल और कठिन हो जाएगा।

मैं Moose की सिफारिश को दूसरी बार दूंगा, इसके इंटरफ़ेस में ऑब्जेक्ट सृजन और प्रारंभिकरण का एक बेहतर पृथक्करण शामिल है जो ऊपर दिए गए मेरे उदाहरण की तुलना में आमतौर पर काम करता है।

+0

धन्यवाद, यह सबसे आसान तरीका है कुछ है कि काम करता है के लिए मेरे वर्तमान कोड में परिवर्तित करने लगता है। – Zitrax

30

अपने सभी निर्माता कर रहा है अपने उदाहरण के रूप में माता पिता के निर्माता (बुला रहा है, तो आप सब पर एक लिखने की जरूरत नहीं है, बस इसे बाहर छोड़ने के लिए और माता पिता होगा कहा जा; तुम सिर्फ यह सुनिश्चित करें कि वस्तु सही प्रकार में आशीर्वाद दिया गया है की जरूरत है:

package Parent; 
use strict; 
use warnings; 

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

    # do something with @args 

    return bless {}, $class; 
} 
1; 

आप उपरोक्त कोड का उपयोग करें और एक Child वर्ग use parent 'Parent'; साथ घोषित है तो जनक निर्माता ठीक से एक बच्चे का निर्माण करेगी

यदि ,

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; 

लेकिन जब आप मिश्रण, आप हर कदम पर ऐसा करना सही फैसला करने के लिए की जरूरत में कई विरासत लाने: आप बच्चे में कुछ गुण जोड़ने की जरूरत है, तो आप क्या था काफी हद तक सही है रास्ते से। इसका अर्थ यह है कि प्रत्येक वर्ग के लिए एक कस्टम कन्स्ट्रक्टर जो निर्णय लेता है कि बच्चे में माता-पिता 1 और माता-पिता 2 के गुणों को कैसे विलय करना है, और अंततः परिणामी वस्तु को बाल वर्ग में आशीर्वाद देता है। यह जटिलता कई कारणों में से एक है क्यों एकाधिक विरासत खराब डिजाइन पसंद है। क्या आपने कुछ वस्तुओं को भूमिकाओं में स्थानांतरित करके संभवतः अपने ऑब्जेक्ट विरासत को फिर से डिजाइन करने पर विचार किया है? इसके अलावा, आप Moose जैसे कुछ व्यस्त कार्य करने के लिए ऑब्जेक्ट फ्रेमवर्क को नियोजित करना चाहेंगे। आजकल कस्टम कन्स्ट्रक्टर लिखना शायद ही कभी जरूरी है।

(अंत में, आप चर $a और $b का उपयोग कर से बचना चाहिए, वे पर्ल में अलग व्यवहार किया जाता के रूप में वे प्रकार कार्यों में इस्तेमाल किया चर और कुछ अन्य का निर्माण-इन कर रहे हैं।)

5

एकाधिक विरासत का उपयोग करते समय, डिफ़ॉल्ट विधि समाधान आदेश उप-पैरा है।मैं दृढ़ता से सुझाव है कि आप मॉड्यूल को

use mro 'c3'; 

जोड़ सकते हैं और है कि आप

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

अल्फा का उपयोग कर श्रृंखला में अगले निर्माता फोन और बीटा इस काम करने के लिए भी ऐसा ही करना होगा।

रेफरी: mro