2012-10-19 11 views
6

मैं एक आधार वर्ग, फू :: बेस नाम है, मैं अपने तरीकों के वारिस के लिए एक दायरे में कुछ सबरूटीन्स नाम आयात करने की आवश्यकता है, जैसे 'नए' और:पर्ल: बेस क्लास से सबराउटिन कैसे आयात करें?

package Foo::Base; 

sub new { ... } 

sub import { 
    no strict 'refs'; 

    my $caller = caller; 

    *{"${caller}::my_sub"} = sub { 1 }; 
} 

1; 

तो, मैं इस आधार उपयोग करने की आवश्यकता मेरी दूसरी कक्षा में वर्ग, फू :: बाल:

use base 'Foo::Base'; 

... और यह विरासत के लिए काम करता है, लेकिन यह एक दायरे में 'my_sub' आयात नहीं करता। मैं स्ट्रिंग जोड़ सकते हैं

use Foo::Base; 
इसके लिए

और यह मदद करता है, लेकिन मैं कुछ इस तरह लिखने के लिए नहीं करना चाहती:

use base 'Foo::Base'; 
use Foo::Base; 

यह वह जगह है अजीब की तरह लग रहा है ... वहाँ के लिए कोई सुझाव है यह समस्या?

उत्तर

6

जब आप use base लिखते हैं, तो आप base मॉड्यूल की सुविधाओं का उपयोग कर रहे हैं। और आप इसे मॉड्यूल का पैरामीटर पास कर रहे हैं जिसे आप अपनी बेस क्लास बनना चाहते हैं।

एक ओओ आईएस-ए रिश्ते में, कोई आयात आवश्यक नहीं है। आप ओओ-पैटर्न के साथ विधियों को कॉल करते हैं: $object_or_class->method_name(@args)। कभी कभी मतलब है कि आप परवाह नहीं है कि जो invocant है, इसलिए जैसे:

sub inherited_util { 
    my (undef, @args) = @_; 
    ... 
} 

या

sub inherited2 { 
    shift; 
    ... 
} 

हालांकि, अगर आप उपयोग करने के लिए उपयोगिताओं आधार मॉड्यूल और इनहेरिट में परिभाषित चाहते उस मॉड्यूल में परिभाषित वर्ग व्यवहार से, तो यह वही है जो दो उपयोग कथन दर्शाते हैं।

फिर भी, यदि आपके पास दो अलग-अलग प्रकार के व्यवहार हैं जो आप मॉड्यूल में उपयोग करना चाहते हैं, तो संभवतः उपयोगिता प्रकार की चीजों को अपने मॉड्यूल में विभाजित करना और दोनों मॉड्यूल से इसका उपयोग करना बेहतर है। किसी भी तरह से, स्पष्ट व्यवहार अक्सर निहित से बेहतर होता है।

sub import { 
    shift; 
    my ($inherit_flag) = @_; 
    my $inherit 
     = lc($inherit_flag) ne 'inherit' ? 0 
     : shift() && !!shift()    ? 1 
     :         0 
     ; 
    if ($inherit) { 
     no strict 'refs'; 
     push @{caller().'::ISA'}, __PACKAGE__; 
     ... 
    } 
    ... 
} 

कि जिस तरह से, मैं प्रयोगों की एक स्पष्ट बंडलिंग के साथ एक फोन करना:

हालांकि, मैं इस पैटर्न से पहले इस्तेमाल किया है।

use UtilityParent inherit => 1, qw<normal args>; 
+0

हां, यह मोजो :: बेस या कक्षा :: सरल, धन्यवाद के समान है! लेकिन मैंने बेहतर कोड आर्किटेक्चर के लिए छोड़ने का फैसला किया =) – shootnix

14

आपके द्वारा किए जा रहे कार्यों को करने के दो कारण हैं, दोनों खराब हैं।

सबसे पहले आप किसी कारण से अपने मूल वर्ग से विधियों को आयात करने की कोशिश कर रहे हैं ...। शायद आप गलत समझें कि ओओ कैसे काम करता है। आपको ऐसा करने की ज़रूरत नहीं है। बस विरासत विधियों को विधियों के रूप में कॉल करें और जब तक कि वे विधियां कुछ निराशाजनक न हों, यह ठीक काम करेगी।

अधिकतर यह मिश्रित उपयोग मॉड्यूल है जहां इनमें से कुछ विधियां हैं और इनमें से कुछ आयातित कार्य हैं। और इसके लिए आप कर सकते हैं ...

use base 'Foo::Base'; 
use Foo::Base; 

और आपने सही ढंग से देखा कि यह अजीब दिखता है ... क्योंकि यह अजीब तरह का है।एक वर्ग जो निर्यात भी मुहावरे मिश्रण कर रहा है, और यह अजीब उपयोग पैटर्न में परिणामस्वरूप जा रहा है।

सर्वोत्तम काम करना है कि कार्यों को निर्यात करने के बजाय कक्षा को फिर से डिजाइन करना, या तो अपने मॉड्यूल में कार्यों को विभाजित करना, या उन्हें कक्षा विधियां बनाना है। यदि कार्यों में वास्तव में कक्षा के साथ बहुत कुछ नहीं है, तो उन्हें स्पिन करने के लिए सबसे अच्छा है। यदि वे कक्षा से संबंधित हैं, तो उन्हें कक्षा के तरीके बनाएं।

use base 'Foo::Base'; 

Foo::Base->some_function_that_used_to_be_exported; 

यह इंटरफ़ेस बेमेल समाप्त, और एक बोनस के रूप में, उपवर्गों किसी भी अन्य विधि की तरह वर्ग विधि व्यवहार को ओवरराइड कर सकते हैं।

package Bar; 

use base 'Foo::Base'; 

# override 
sub some_function_that_used_to_be_exported { 
    my($class, @args) = @_; 

    ...do something extra maybe... 

    $class->SUPER::some_function_that_used_to_be_exported(@args); 

    ...and maybe something else... 
} 

आप आधार वर्ग पर नियंत्रण नहीं है, तो आप अभी भी इंटरफ़ेस एक उपवर्ग जो तरीकों में निर्यात कार्यों बदल जाता है लिख कर समझदार बना सकते हैं।

package SaneFoo; 

use base 'Foo::Base'; 

# For each function exported by Foo::Base, create a wrapper class 
# method which throws away the first argument (the class name) and 
# calls the function. 
for my $name (@Foo::Base::EXPORT, @Foo::Base::EXPORT_OK) { 
    my $function = Foo::Base->can($name); 
    *{$name} = sub { 
     my $class = shift; 
     return $function->(@_); 
    }; 
} 
+0

असल में मैं इस वर्ग में कुछ वाक्य रचनात्मक चीनी जोड़ना चाहता था, बिल्कुल मोजो :: बेस में, लेकिन आप सही हैं, धन्यवाद - मेरे वर्तमान के लिए ओवरकिल कार्य, और अगर मैं मोजो :: बेस का उपयोग कर सकता, तो मैंने किया होता, लेकिन मैं नहीं कर सकता। – shootnix

+0

उस मामले में मोजो :: बेस जैसे 'फू -बेस' का उपयोग करें। मैं मूस मार्ग पर जाने की सिफारिश नहीं करता जहां निर्यात और विरासत दोनों में 'फू का उपयोग करें'। यह जे :: रैंडम :: मॉड्यूल के लिए ऐसा करने के लिए बहुत से सम्मेलनों को तोड़ देता है। जब तक यह आपके स्वयं के प्रोजेक्ट के मूस समकक्ष नहीं होगा। Soooo ... आप Mojo :: बेस का उपयोग क्यों नहीं कर सकते? – Schwern

1

की? "लेकिन क्यों नहीं फू में आयात :: बाल काम करता है", यहाँ एक प्रोग्राम है जो वास्तव में क्या हो रहा है उल्लेख होगा थोड़ा और प्रश्न को स्पष्ट करने के लिए:

use Foo::Child; 
print my_sub(); # Really? Yes, really! 
print Foo::Child::my_sub()," done\n"; 

और फू :: बेस को यह जोड़ा :: आयात() दिनचर्या:

print "Caller is $caller\n"; 

जब आप इस चलाने के लिए, तो आप इस आउटपुट के रूप में देखें:

Caller is main 
1 
Undefined subroutine &Foo::Child::my_sub called at foo_user.pl line 4. 

हम फू :: बेस रिपोर्टिंग देखते हैं, हमें यह बताते हुए कि कॉलर कौन है: यह मुख्य कार्यक्रम है! हम '1' देखते हैं, जो साबित करता है कि हाँ, मुख्य :: my_sub अब मौजूद है, और फिर विफलता क्योंकि आयात गलत नामस्थान पर गया था।

यह क्यों है? चूंकि आयात प्रक्रिया को मुख्य कार्यक्रम द्वारा संभाला जा रहा है। Foo :: Foo :: Child में किसी भी चीज़ द्वारा बेस का आयात नहीं किया जाता है; इसे मॉड्यूल लोड करने की प्रक्रिया में मुख्य कार्यक्रम द्वारा बुलाया जा रहा है। यदि आप वास्तव में, वास्तव में फू :: चाइल्ड में आयात करने के तरीकों के विपरीत सबस को मजबूर करना चाहते हैं, तो आपको स्पष्ट रूप से इसे Foo :: Child में होने की आवश्यकता है। 'फू :: बेस' का उपयोग करें, क्योंकि यह कॉलर के रूप में Foo :: Child के साथ आयात निष्पादित करता है; यदि आप आयात पर जोर देते हैं, लेकिन डबल उपयोग आपको बहुत अधिक बनाता है, तो आप 'उपयोग आधार' के ठीक बाद Foo :: Base :: import() को कॉल कर सकते हैं। यह वही है जो डबल 'उपयोग' वैसे भी करता है।

फिर भी, मुझे श्वेर्न की कक्षा विधियों को बेहतर पसंद है, और मैं उस विकल्प की अनुशंसा करता हूं।

संबंधित मुद्दे