2011-06-19 16 views
5

मैं सोच रहा था कि मैं वास्तव में समझ में नहीं आता कि उत्प्रेरक में सब कुछ संदर्भ वस्तु का उपयोग क्यों करता है। लगता है कि बस के बारे में सब कुछहम उत्प्रेरक के संदर्भ वस्तु का उपयोग क्यों करते हैं? इसका उद्देश्य क्या है?

my ($self, $c) = @_; 

साथ शुरू होता है हम एक उत्प्रेरक के मॉडल के साथ DBIC लपेट और

$c->model('DBIC::Table') ... 

या हो सकता है हम करते हैं

$c->log->warn('foo'); 

साथ खत्म हो, लेकिन मैं क्यों समझ में नहीं आता क्या हम सिर्फ

log('warn', 'foo'); # or whatever the API for some log library is. 

संदर्भ वस्तु के बावजूद हम सबकुछ क्यों करते हैं? क्या यह विशेष बनाता है?

उत्तर

5

अगर मैं समझता हूं कि सही तरीके से क्या चल रहा है (और मैंने उत्प्रेरक को बहुत कठिन नहीं देखा है, तो यह आसानी से संभव है), संदर्भ चर कॉलिंग फ्रेमवर्क है। जब कोई अनुरोध आता है, तो ढांचा सभी जानकारी स्वयं में बनाता है और कॉल आपकी कक्षा में एक विधि को स्वयं से गुजरती है ताकि आपकी विधि में उस सारी जानकारी और बाकी ढांचे तक पहुंच हो। आप पाते हैं कि inversion of control (या आईओसी) पढ़ने के बारे में आपको समझने में मदद मिलती है।

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

2

पर्ल और अन्य भाषाओं में एक आम मुहावरे "ईश्वर" वस्तुओं को पारित करना है जो प्रभावी रूप से नामस्थान पर एक इंटरफ़ेस प्रदान करते हैं। यह आपके नामस्थान में आयात किए जाने वाले सभी कार्यों की आवश्यकता के बजाय कॉलिंग विधियों को सक्षम बनाता है। इन नामस्थानों में से प्रत्येक को अलग-अलग रनटाइम डेटा (ऑब्जेक्ट के उदाहरण) के साथ भी अनुकूलित किया जा सकता है।

यदि आपको ऑब्जेक्ट पर कॉलिंग विधियों के सिंटैक्स पसंद नहीं हैं, तो ऐसा लगता है कि आप जो खोज रहे हैं वह जावास्क्रिप्ट के with ब्लॉक जैसा कुछ है।

use warnings; 
use strict; 
use Carp(); 

sub with ($&) { 
    my ($obj, $code) = @_; 
    my $auto = (caller).'::AUTOLOAD'; 
    no strict 'refs'; 
    local *$auto = sub { 
     my ($name) = $$auto =~ /([^:]+)$/; 
     my $method = $obj->can($name) 
        || $obj->can(lcfirst $name) 
      or Carp::croak "no method '$name' on '$obj' in with block"; 
     unshift @_, $obj; 
     goto &$method 
    }; 
    $code->() 
} 

नकली वस्तु को देखते हुए:

{package Obj; 
    sub new {bless []} 
    sub log {shift; say "logging @_"} 
    sub model {shift; say "setting model to @_"} 
} 

फिर आप लिख सकते हैं:

my $c = Obj->new; 

with $c => sub { 
    model('DBIC::Table'); 
    Log('hello world'); # ucfirst 
    &log('hello again'); # or with a & since 'log' is a builtin 
}; 
पर्ल एक देशी संरचना है कि यह करता है नहीं करता है, यह एक बनाने के लिए उपकरण प्रदान करता है

प्रिंट कौन सा:

 
setting model to DBIC::Table 
logging hello world 
logging hello again 

मज़े करें, बस ध्यान रखें कि पहले से परिभाषित सबराउटिन के निर्मित नाम या नाम with ब्लॉक में ओवरराइड नहीं किए जाएंगे। आप नाम के ucfirst संस्करण का उपयोग कर सकते हैं या बस उन मामलों में विधि को कॉल कर सकते हैं। with ब्लॉक में सभी नए सबराउटिन को माता-पिता Log('hello') और Log 'hello' के साथ भी कॉल नहीं किया जाना चाहिए क्योंकि नाम संकलन समय पर ज्ञात नहीं है।

+0

यह वास्तव में वाक्यविन्यास के बारे में कोई सवाल नहीं था ... हालांकि मैं राकुडो के तरीकों को कॉल करने का तरीका पसंद करता हूं ... – xenoterracide

+1

@xenoterracide => आपने पूछा कि उत्प्रेरक ने क्यों लिखा है '$ c-> log-> चेतावनी (...) 'लॉग के बजाय (चेतावनी => ...)'। यह एक वाक्य रचनात्मक अंतर है। इसका कारण यह है कि उत्प्रेरक विचारों के लेखक सबसे अच्छे थे। तो मैंने आपको जिस तरह से चाहते थे उसे लिखने का एक तरीका दिया (हालांकि इस मामले में, यह 'लॉग() -> चेतावनी (...)' होगा क्योंकि उत्प्रेरक की 'लॉग' विधि काम करती है), किस प्रकार का क्या आप उम्मीद कर रहे थे? –

+0

संदर्भ वस्तु के माध्यम से सब कुछ क्यों किया जाता है, इसके बारे में और पूछना, यहां तक ​​कि बाहरी सामान भी इसके माध्यम से उपयोग किया जाता है। सिंटैक्स का सही संदर्भ संदर्भ वस्तु के माध्यम से क्यों अधिक स्पष्ट है। कहने के विरोध में, बस एक लॉग एपीआई का उपयोग कर सीधे। – xenoterracide

1

कोई भी आमतौर पर उत्प्रेरक :: नियंत्रक में जो कुछ भी दिखाया गया है उसे लिखता है। अब आपको याद रखना चाहिए कि उत्प्रेरक नियंत्रक आपका यूआरएल मैपिंग करने के लिए मौजूद है। निश्चित रूप से, नियंत्रक में बहुत से फ़ंक्शन आयात करना संभव है, लेकिन जब उत्प्रेरक स्वयं log फ़ंक्शन आयात करता है, तो आप यूआरएल मैपिंग के लिए इस फ़ंक्शन का उपयोग कैसे करते हैं?

उदाहरण के लिए sub log : Local { ... }। जल्द ही यह संभव नहीं होगा, या यह अधिक जटिल होगा तो यह होना चाहिए। एक नियंत्रक के पास लगभग कोई कार्य नहीं होता है, ताकि आपको बहुत से कार्यों को याद रखने की आवश्यकता न हो और कोई संघर्ष न हो।

इसी कारण से पर्ल स्वयं विशेष चर में विशेष पात्रों का चयन करना चुनता है। $/, $_, $] और इसी तरह की तरह। निश्चित रूप से वे $INPUT_RECORD_SEPARATOR या $RS डिफ़ॉल्ट के रूप में भी उपयोग कर सकते हैं, लेकिन फिर आपको उन्हें जानने की आवश्यकता है, और यदि आप सभी विशेष चर नहीं जानते हैं तो शायद यह आपके कोड से संघर्ष कर सकता है।

एक अन्य कारण यह है कि $c पर आपके अतिरिक्त विशेषताओं को आप कुछ संदर्भ देते हैं। उदाहरण के लिए आप $c->log->disable('warn', 'error') के साथ लॉगिंग को सक्षम या अक्षम कर सकते हैं या बस उन्हें सक्षम कर सकते हैं। यह संदर्भ गहरा नियंत्रक में सही ढंग से पारित किया गया है। और वे वैश्विक नहीं हैं, आप उन्हें किसी अन्य राज्य में हर अनुरोध पर सेट कर सकते हैं।

एक और कारण यह है कि आपके द्वारा उपयोग की जाने वाली अतिरिक्त कार्यक्षमता और कभी-कभी कॉन्फ़िगरेशन फ़ाइल या अन्य चीजों को पढ़ने की आवश्यकता होती है। प्रत्येक अनुरोध के लिए आप जिस ऑब्जेक्ट को पास करते हैं उसका उपयोग करना (प्रत्येक $c प्रत्येक अनुरोध के लिए विशेष है) और प्रत्येक अनुरोध के लिए संशोधित किया जा सकता है, आपके एक्सटेंशन को आपके आवेदन से जानकारी का अनुरोध करने या किसी विशिष्ट अनुरोध के लिए राज्य को संभालने की संभावना देता है।

लेकिन यदि आप अभी भी यह नहीं चाहते हैं, तो आपको $c का उपयोग करने के लिए मजबूर नहीं किया जाता है। उदाहरण के लिए आप लॉग :: लॉग 4Perl मैन्युअल रूप से लोड कर सकते हैं, और इसके लिए एक विशेष कॉन्फ़िगरेशन का उपयोग कर सकते हैं, और $c->log का उपयोग नहीं कर सकते हैं। या आप अपने आप से बहुत सारे काम आयात कर सकते हैं। लेकिन मुझे लगता है कि नेमस्पेस को प्रदूषित नहीं करना और आपको प्रत्येक अनुरोध के लिए कुछ विशेष करने की संभावना देना एक अच्छा डिफ़ॉल्ट है।

और कम से कम कोई नियम नहीं है कि आपको $c का उपयोग करना होगा। उदाहरण के लिए, मैं स्वयं डेटटाइम का सीधे उपयोग करता हूं और नई ऑब्जेक्ट्स बनाता हूं और उत्प्रेरक :: प्लगइन :: डेटटाइम का उपयोग नहीं करता जो मुझे $c->datetime करने की अनुमति देता है। और मुझे अंतिम करने का कोई लाभ नहीं दिख रहा है। सिर्फ इसलिए कि $c तक फैले बहुत से प्लगइन मौजूद हैं, इसका मतलब यह नहीं है कि वे उपयोगी हैं या आपको उनका उपयोग करना होगा।

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